Kaynağa Gözat

first commit

latyas 7 yıl önce
işleme
685084c40a
100 değiştirilmiş dosya ile 31813 ekleme ve 0 silme
  1. 15 0
      .gitignore
  2. 7 0
      CHANGELOG.md
  3. 26 0
      CMakeLists.txt
  4. 202 0
      LICENSE
  5. 23 0
      README.md
  6. 44 0
      cmake/CMakeLists.txt
  7. 3 0
      cmake/README.md
  8. 34 0
      cmake/common.cmake
  9. 53 0
      cmake/compile-flags.cmake
  10. 13 0
      cmake/dump-config.cmake
  11. 36 0
      cmake/executable.cmake
  12. 3 0
      cmake/fix-9985.cmake
  13. 65 0
      cmake/macros.cmake
  14. 12 0
      cmake/macros.internal.cmake
  15. 22 0
      cmake/toolchain.cmake
  16. 250 0
      lds/kendryte.ld
  17. 33 0
      lib/CMakeLists.txt
  18. 29 0
      lib/bsp/config/fpioa_cfg.c
  19. 42 0
      lib/bsp/config/fpioa_cfg.h
  20. 296 0
      lib/bsp/crt.S
  21. 37 0
      lib/bsp/entry.c
  22. 112 0
      lib/bsp/entry_user.c
  23. 244 0
      lib/bsp/include/atomic.h
  24. 141 0
      lib/bsp/include/dump.h
  25. 71 0
      lib/bsp/include/entry.h
  26. 1340 0
      lib/bsp/include/env/encoding.h
  27. 47 0
      lib/bsp/include/interrupt.h
  28. 99 0
      lib/bsp/include/platform.h
  29. 209 0
      lib/bsp/include/printf.h
  30. 36 0
      lib/bsp/include/sleep.h
  31. 46 0
      lib/bsp/include/syscalls.h
  32. 198 0
      lib/bsp/include/util.h
  33. 66 0
      lib/bsp/interrupt.c
  34. 668 0
      lib/bsp/printf.c
  35. 38 0
      lib/bsp/sleep.c
  36. 641 0
      lib/bsp/syscalls.c
  37. 365 0
      lib/drivers/aes.c
  38. 441 0
      lib/drivers/audio_bf.c
  39. 276 0
      lib/drivers/clint.c
  40. 55 0
      lib/drivers/common.c
  41. 716 0
      lib/drivers/dmac.c
  42. 293 0
      lib/drivers/dvp.c
  43. 5398 0
      lib/drivers/fpioa.c
  44. 86 0
      lib/drivers/gpio.c
  45. 184 0
      lib/drivers/gpiohs.c
  46. 150 0
      lib/drivers/hard_fft.c
  47. 196 0
      lib/drivers/i2c.c
  48. 702 0
      lib/drivers/i2s.c
  49. 257 0
      lib/drivers/include/aes.h
  50. 329 0
      lib/drivers/include/audio_bf.h
  51. 323 0
      lib/drivers/include/clint.h
  52. 357 0
      lib/drivers/include/common.h
  53. 1686 0
      lib/drivers/include/dmac.h
  54. 284 0
      lib/drivers/include/dvp.h
  55. 980 0
      lib/drivers/include/fpioa.h
  56. 176 0
      lib/drivers/include/gpio.h
  57. 53 0
      lib/drivers/include/gpio_common.h
  58. 267 0
      lib/drivers/include/gpiohs.h
  59. 271 0
      lib/drivers/include/hard_fft.h
  60. 434 0
      lib/drivers/include/i2c.h
  61. 1009 0
      lib/drivers/include/i2s.h
  62. 50 0
      lib/drivers/include/io.h
  63. 361 0
      lib/drivers/include/otp.h
  64. 462 0
      lib/drivers/include/plic.h
  65. 603 0
      lib/drivers/include/rtc.h
  66. 94 0
      lib/drivers/include/sha256.h
  67. 449 0
      lib/drivers/include/spi.h
  68. 43 0
      lib/drivers/include/sysclock.h
  69. 1016 0
      lib/drivers/include/sysctl.h
  70. 290 0
      lib/drivers/include/timer.h
  71. 209 0
      lib/drivers/include/uart.h
  72. 223 0
      lib/drivers/include/uarths.h
  73. 189 0
      lib/drivers/include/wdt.h
  74. 602 0
      lib/drivers/otp.c
  75. 204 0
      lib/drivers/plic.c
  76. 581 0
      lib/drivers/rtc.c
  77. 135 0
      lib/drivers/sha256.c
  78. 615 0
      lib/drivers/spi.c
  79. 69 0
      lib/drivers/sysclock.c
  80. 1726 0
      lib/drivers/sysctl.c
  81. 214 0
      lib/drivers/timer.c
  82. 194 0
      lib/drivers/uart.c
  83. 97 0
      lib/drivers/uarths.c
  84. 120 0
      lib/drivers/wdt.c
  85. 366 0
      lib/firmware/include/font.h
  86. 82 0
      lib/firmware/include/lcd.h
  87. 113 0
      lib/firmware/include/nt35310.h
  88. 26 0
      lib/firmware/include/ov2640.h
  89. 52 0
      lib/firmware/include/ov5640.h
  90. 287 0
      lib/firmware/include/ov5640cfg.h
  91. 47 0
      lib/firmware/include/sd3068.h
  92. 113 0
      lib/firmware/include/w25qxx.h
  93. 210 0
      lib/firmware/lcd.c
  94. 115 0
      lib/firmware/nt35310.c
  95. 243 0
      lib/firmware/ov2640.c
  96. 82 0
      lib/firmware/ov5640.c
  97. 195 0
      lib/firmware/sd3068.c
  98. 660 0
      lib/firmware/w25qxx.c
  99. 71 0
      lib/math/fastexp.c
  100. 116 0
      lib/math/fastexp.h

+ 15 - 0
.gitignore

@@ -0,0 +1,15 @@
+autom4te.cache
+build
+build_i
+config.log
+config.status
+Makefile
+.DS_Store
+!/regression/Makefile
+.vs
+.vscode
+CMakeSettings.json
+.idea
+*.tar
+*.tar.*
+cmake-build-*

+ 7 - 0
CHANGELOG.md

@@ -0,0 +1,7 @@
+Changelog for Kendryte K210
+======
+
+## 0.1.0
+
+Kendryte K210 first SDK with FreeRTOS, have fun. 
+

+ 26 - 0
CMakeLists.txt

@@ -0,0 +1,26 @@
+### This file is used for build example projects.
+
+# set this will supress some warnings
+set(BUILDING_SDK "yes" CACHE INTERNAL "")
+
+# basic config
+if (NOT PROJ)
+    message(FATAL_ERROR "PROJ must be set. e.g. -DPROJ=hello_world")
+endif ()
+cmake_minimum_required(VERSION 3.0)
+include(./cmake/common.cmake)
+project(${PROJ})
+
+# config self use headers
+include(./cmake/macros.internal.cmake)
+header_directories(${SDK_ROOT}/lib)
+# build library first
+add_subdirectory(lib)
+
+# TODO
+#add_subdirectory(third_party)
+
+# compile project
+add_source_files(src/${PROJ}/*.c src/${PROJ}/*.s src/${PROJ}/*.S src/${PROJ}/*.cpp)
+include(./cmake/executable.cmake)
+

+ 202 - 0
LICENSE

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   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.

+ 23 - 0
README.md

@@ -0,0 +1,23 @@
+Kendryte K210 standalone SDK
+======
+
+This SDK is for Kendryte K210 without OS support.
+If you have any questions, please be free to contact us.
+
+# Usage
+
+If you want to start a new project, for instance, `hello_world`, you only need to:
+
+`mkdir` your project in `src/`, `cd src && mkdir hello_world`, then put your codes in it, and build it.
+
+```shell
+mkdir build && cd build
+cmake .. -DPROJ=<ProjectName> -DTOOLCHAIN=/opt/riscv-toolchain/bin && make
+```
+
+You will get 2 key files, `hello_world` and `hello_world.bin`.
+
+1. If you are using JLink to run or debug your program, use `hello_world`
+2. If you want to flash it in UOG, using `hello_world.bin`, then using flash-tool(s) burn <ProjectName>.bin to your flash.
+
+This is very important, don't make a mistake in files.

+ 44 - 0
cmake/CMakeLists.txt

@@ -0,0 +1,44 @@
+### This file is used for build library standalone.
+
+# set this will supress some warnings
+set(BUILDING_SDK "yes" CACHE INTERNAL "")
+
+# basic config
+cmake_minimum_required(VERSION 3.0)
+include(./common.cmake)
+project(kendryte)
+
+# config self use headers
+include(./macros.internal.cmake)
+header_directories(${SDK_ROOT}/lib)
+
+# include lib make file
+include(../lib/CMakeLists.txt)
+
+# find headers files to INSTALL
+file(GLOB_RECURSE LIB_HEADERS
+        "../lib/*.h"
+        "../lib/*.hpp"
+        )
+set_target_properties(kendryte PROPERTIES PUBLIC_HEADER "${LIB_HEADERS}")
+
+# copy .a file and headers
+install(TARGETS kendryte
+        EXPORT kendryte
+        ARCHIVE
+        DESTINATION ${CMAKE_BINARY_DIR}/archive
+        PUBLIC_HEADER DESTINATION ${CMAKE_BINARY_DIR}/archive/include
+        )
+
+# copy utils files
+install(DIRECTORY
+        ../lds
+        ../utils
+        ../cmake
+        DESTINATION ${CMAKE_BINARY_DIR}/archive
+        PATTERN "*internal*" EXCLUDE
+        PATTERN "CMakeLists.txt" EXCLUDE
+        )
+
+# show information
+include(./dump-config.cmake)

+ 3 - 0
cmake/README.md

@@ -0,0 +1,3 @@
+prepend `common.cmake` before
+
+append `executable.cmake` after

+ 34 - 0
cmake/common.cmake

@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.0)
+
+include(${CMAKE_CURRENT_LIST_DIR}/macros.cmake)
+
+global_set(CMAKE_C_COMPILER_WORKS 1)
+global_set(CMAKE_CXX_COMPILER_WORKS 1)
+
+global_set(CMAKE_SYSTEM_NAME "Generic")
+if (NOT CMAKE_BUILD_TYPE)
+    global_set(CMAKE_BUILD_TYPE Debug)
+else ()
+    if ((NOT CMAKE_BUILD_TYPE STREQUAL "Debug") AND (NOT CMAKE_BUILD_TYPE STREQUAL "Release"))
+        message(FATAL_ERROR "CMAKE_BUILD_TYPE must either be Debug or Release instead of ${CMAKE_BUILD_TYPE}")
+    endif ()
+endif ()
+
+# - Debug & Release
+IF (CMAKE_BUILD_TYPE STREQUAL Debug)
+    add_definitions(-DDEBUG=1)
+ENDIF ()
+
+# definitions in macros
+add_definitions(-DCONFIG_LOG_LEVEL=LOG_VERBOSE -DCONFIG_LOG_ENABLE -DCONFIG_LOG_COLORS -DLOG_KERNEL -D__riscv64 -DFPGA_PLL)
+
+if (NOT SDK_ROOT)
+    get_filename_component(_SDK_ROOT ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)
+    global_set(SDK_ROOT ${_SDK_ROOT})
+endif ()
+
+include(${CMAKE_CURRENT_LIST_DIR}/toolchain.cmake)
+
+include(${CMAKE_CURRENT_LIST_DIR}/compile-flags.cmake)
+
+include(${CMAKE_CURRENT_LIST_DIR}/fix-9985.cmake)

+ 53 - 0
cmake/compile-flags.cmake

@@ -0,0 +1,53 @@
+add_compile_flags(LD
+        -nostartfiles
+        -static
+        -Wl,--gc-sections
+        -Wl,-static
+        -Wl,--start-group
+        -Wl,--whole-archive
+        -Wl,--no-whole-archive
+        -Wl,--end-group
+        -Wl,-EL
+        -T ${SDK_ROOT}/lds/kendryte.ld
+        )
+
+# C Flags Settings
+add_compile_flags(BOTH
+        -mcmodel=medany
+        -fno-common
+        -ffunction-sections
+        -fdata-sections
+        -fstrict-volatile-bitfields
+        -O0
+        -ggdb
+        )
+
+add_compile_flags(C -std=gnu11)
+add_compile_flags(CXX -std=gnu++17)
+
+if (BUILDING_SDK)
+    add_compile_flags(BOTH
+            -Wall
+            -Werror=all
+            -Wno-error=unused-function
+            -Wno-error=unused-but-set-variable
+            -Wno-error=unused-variable
+            -Wno-error=deprecated-declarations
+            -Wextra
+            -Werror=frame-larger-than=65536
+            -Wno-unused-parameter
+            -Wno-sign-compare
+            -Wno-error=missing-braces
+			-Wno-error=return-type
+			-Wno-error=pointer-sign
+			-Wno-missing-braces
+			-Wno-pointer-to-int-cast
+			-Wno-strict-aliasing
+			-Wno-implicit-fallthrough
+            )
+
+    add_compile_flags(C -Wno-old-style-declaration)
+else ()
+    add_compile_flags(BOTH -L${SDK_ROOT}/include/)
+endif ()
+

+ 13 - 0
cmake/dump-config.cmake

@@ -0,0 +1,13 @@
+message("")
+message("Project: ${PROJECT_NAME}")
+message("  TOOLCHAIN=${TOOLCHAIN}")
+message("  KENDRYTE IDE=${KENDRYTE_IDE}")
+message("")
+message("  CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
+message("  CMAKE_C_COMPILER=${CMAKE_C_COMPILER}")
+message("  CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}")
+message("  CMAKE_LINKER=${CMAKE_LINKER}")
+message("  CMAKE_OBJCOPY=${CMAKE_OBJCOPY}")
+message("Makefile created.")
+message("")
+message("")

+ 36 - 0
cmake/executable.cmake

@@ -0,0 +1,36 @@
+if (NOT BUILDING_SDK)
+    add_library(kendryte STATIC IMPORTED)
+    set_property(TARGET kendryte PROPERTY IMPORTED_LOCATION ${SDK_ROOT}/libmaix.a)
+    include_directories(${SDK_ROOT}/include/)
+endif ()
+
+add_executable(${PROJECT_NAME} ${SOURCE_FILES})
+# add_dependencies(${PROJECT_NAME} kendryte) # TODO: third_party
+# target_link_libraries(${PROJECT_NAME} kendryte) # TODO: third_party
+# link_directories(${CMAKE_BINARY_DIR})
+
+set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C)
+
+target_link_libraries(${PROJECT_NAME}
+        -Wl,--start-group
+        gcc m c kendryte
+        -Wl,--end-group
+        )
+
+IF(SUFFIX)
+    SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SUFFIX ${SUFFIX})
+ENDIF()
+
+#message("CMAKE_OBJCOPY=${CMAKE_OBJCOPY}")
+
+# Build target
+add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+        COMMAND ${CMAKE_OBJCOPY} --output-format=binary ${CMAKE_BINARY_DIR}/${PROJECT_NAME}${SUFFIX} ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.bin
+        DEPENDS ${PROJECT_NAME}
+        COMMENT "Generating .bin file ...")
+
+
+add_custom_target(firmware DEPENDS ${PROJECT_NAME}.firmware.bin)
+
+# show information
+include(${CMAKE_CURRENT_LIST_DIR}/dump-config.cmake)

+ 3 - 0
cmake/fix-9985.cmake

@@ -0,0 +1,3 @@
+### http://www.cmake.org/Bug/view.php?id=9985
+string(REPLACE "-rdynamic" "" CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS}")
+string(REPLACE "-rdynamic" "" CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS}")

+ 65 - 0
cmake/macros.cmake

@@ -0,0 +1,65 @@
+macro(global_set Name Value)
+    #  message("set ${Name} to " ${ARGN})
+    set(${Name} "${Value}" CACHE STRING "NoDesc" FORCE)
+endmacro()
+
+macro(condition_set Name Value)
+    if (NOT ${Name})
+        global_set(${Name} ${Value})
+    else ()
+        #        message("exists ${Name} is " ${ARGN})
+    endif ()
+endmacro()
+
+
+set(SOURCE_FILES "" CACHE STRING "Source Files" FORCE)
+macro(add_source_files)
+    #    message(" + add_source_files ${ARGN}")
+    file(GLOB_RECURSE newlist ${ARGN})
+
+    foreach (filepath ${newlist})
+        string(FIND ${filepath} ${CMAKE_BINARY_DIR} found)
+        if (NOT found EQUAL 0)
+            set(SOURCE_FILES ${SOURCE_FILES} ${filepath} CACHE STRING "Source Files" FORCE)
+        endif ()
+    endforeach ()
+endmacro()
+
+function(JOIN VALUES GLUE OUTPUT)
+    string(REGEX REPLACE "([^\\]|^);" "\\1${GLUE}" _TMP_STR "${VALUES}")
+    string(REGEX REPLACE "[\\](.)" "\\1" _TMP_STR "${_TMP_STR}") #fixes escaping
+    set(${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
+endfunction()
+
+global_set(LDFLAGS "")
+global_set(CMAKE_EXE_LINKER_FLAGS "")
+global_set(CMAKE_SHARED_LINKER_FLAGS "")
+global_set(CMAKE_MODULE_LINKER_FLAGS "")
+
+macro(add_compile_flags WHERE)
+    JOIN("${ARGN}" " " STRING_ARGS)
+    if (${WHERE} STREQUAL C)
+        global_set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${STRING_ARGS}")
+
+    elseif (${WHERE} STREQUAL CXX)
+        global_set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STRING_ARGS}")
+
+    elseif (${WHERE} STREQUAL LD)
+        global_set(LDFLAGS "${LDFLAGS} ${STRING_ARGS}")
+        global_set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${STRING_ARGS}")
+        global_set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${STRING_ARGS}")
+        global_set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${STRING_ARGS}")
+
+    elseif (${WHERE} STREQUAL BOTH)
+        add_compile_flags(C ${ARGN})
+        add_compile_flags(CXX ${ARGN})
+
+    elseif (${WHERE} STREQUAL ALL)
+        add_compile_flags(C ${ARGN})
+        add_compile_flags(CXX ${ARGN})
+        add_compile_flags(LD ${ARGN})
+
+    else ()
+        message(FATAL_ERROR "add_compile_flags - only support: C, CXX, BOTH, LD, ALL")
+    endif ()
+endmacro()

+ 12 - 0
cmake/macros.internal.cmake

@@ -0,0 +1,12 @@
+# Add lib headers
+macro(header_directories parent)
+    file(GLOB_RECURSE newList ${parent}/*.h)
+    set(dir_list "")
+    foreach (file_path ${newList})
+        get_filename_component(dir_path ${file_path} DIRECTORY)
+        set(dir_list ${dir_list} ${dir_path})
+    endforeach ()
+    list(REMOVE_DUPLICATES dir_list)
+
+    include_directories(${dir_list})
+endmacro()

+ 22 - 0
cmake/toolchain.cmake

@@ -0,0 +1,22 @@
+if (NOT TOOLCHAIN)
+    message(FATAL_ERROR "TOOLCHAIN must be set, to absolute path of kendryte-toolchain dist/bin folder.")
+endif ()
+
+if (WIN32)
+    set(EXT ".exe")
+else ()
+    set(EXT "")
+endif ()
+
+condition_set(CMAKE_C_COMPILER "${TOOLCHAIN}/riscv64-unknown-elf-gcc${EXT}" CACHE INTERNAL "")
+condition_set(CMAKE_CXX_COMPILER "${TOOLCHAIN}/riscv64-unknown-elf-g++${EXT}" CACHE INTERNAL "")
+condition_set(CMAKE_LINKER "${TOOLCHAIN}/riscv64-unknown-elf-ld${EXT}" CACHE INTERNAL "")
+condition_set(CMAKE_AR "${TOOLCHAIN}/riscv64-unknown-elf-ar${EXT}" CACHE INTERNAL "")
+condition_set(CMAKE_CXX_COMPILER_AR "${CMAKE_AR}${EXT}" CACHE INTERNAL "")
+condition_set(CMAKE_C_COMPILER_AR "${CMAKE_AR}${EXT}" CACHE INTERNAL "")
+condition_set(CMAKE_OBJCOPY "${TOOLCHAIN}/riscv64-unknown-elf-objcopy${EXT}" CACHE INTERNAL "")
+
+get_filename_component(_BIN_DIR "${CMAKE_C_COMPILER}" DIRECTORY)
+if (NOT "${TOOLCHAIN}" STREQUAL "${_BIN_DIR}")
+    message(FATAL_ERROR "CMAKE_C_COMPILER is not in kendryte-toolchain dist/bin folder.")
+endif ()

+ 250 - 0
lds/kendryte.ld

@@ -0,0 +1,250 @@
+/*
+ * The MEMORY command describes the location and size of blocks of memory
+ * in the target. You can use it to describe which memory regions may be
+ * used by the linker, and which memory regions it must avoid.
+ */
+MEMORY
+{
+  /*
+   * Memory with CPU cache.
+   *6M CPU SRAM
+   */
+  ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = (6 * 1024 * 1024)
+  /*
+   * Memory without CPU cache
+   * 6M CPU SRAM
+  */
+  ram_nocache (wxa!ri) : ORIGIN = 0x40000000, LENGTH = (6 * 1024 * 1024)
+}
+
+PROVIDE( _rom_start  = ORIGIN(rom) );
+PROVIDE( _rom_end    = ORIGIN(rom) + LENGTH(rom) );
+PROVIDE( _ram_start  = ORIGIN(ram) );
+PROVIDE( _ram_end    = ORIGIN(ram) + LENGTH(ram) );
+PROVIDE( _io_start   = 0x40000000 );
+PROVIDE( _io_end     = _io_start + LENGTH(ram) );
+PROVIDE( _stack_size = 1 << 17 );
+
+
+/*
+ * The OUTPUT_ARCH command specifies the machine architecture where the
+ * argument is one of the names used in the Kendryte library.
+ */
+OUTPUT_ARCH( "riscv" )
+
+/*
+ * The ENTRY command specifies the entry point (ie. first instruction to
+ * execute). The symbol _start is defined in crt0.S
+ */
+ENTRY(_start)
+
+/*
+ * The GROUP command is special since the listed archives will be
+ * searched repeatedly until there are no new undefined references. We
+ * need this since -lc depends on -lgloss and -lgloss depends on -lc. I
+ * thought gcc would automatically include -lgcc when needed, but
+ * in this file includes it explicitly here and I was seeing link errors
+ * without it.
+ */
+/* GROUP( -lc -lgloss -lgcc ) */
+
+/*
+ * The linker only pays attention to the PHDRS command when generating
+ * an ELF output file. In other cases, the linker will simply ignore PHDRS.
+ */
+PHDRS
+{
+  ram_ro   PT_LOAD;
+  ram_init PT_LOAD;
+  ram      PT_NULL;
+}
+
+/*
+ * This is where we specify how the input sections map to output
+ * sections.
+ */
+SECTIONS
+{
+  /* Program code segment, also known as a text segment */
+  .text :
+  {
+    PROVIDE( _text = ABSOLUTE(.) );
+    /* Initialization code segment */
+    KEEP( *(.text.start) )
+    *(.text.unlikely .text.unlikely.*)
+    *(.text.startup .text.startup.*)
+    /* Normal code segment */
+    *(.text .text.*)
+    *(.gnu.linkonce.t.*)
+
+    . = ALIGN(8);
+    PROVIDE( _etext = ABSOLUTE(.) );
+  } >ram AT>ram :ram_ro
+
+  /* Read-only data segment */
+  .rodata :
+  {
+    *(.rdata)
+    *(.rodata .rodata.*)
+    *(.gnu.linkonce.r.*)
+  } >ram AT>ram :ram_ro
+
+  . = ALIGN(8);
+
+  /* Init array and fini array */
+  .preinit_array :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  } >ram AT>ram :ram_ro
+
+  .init_array :
+  {
+    PROVIDE_HIDDEN (__init_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+    PROVIDE_HIDDEN (__init_array_end = .);
+  } >ram AT>ram :ram_ro
+
+  .fini_array :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+    KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+  } >ram AT>ram :ram_ro
+
+  .ctors :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*crtbegin?.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  } >ram AT>ram :ram_ro
+
+  .dtors :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*crtbegin?.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  } >ram AT>ram :ram_ro
+
+  . = ALIGN(8);
+
+  .lalign :
+  {
+    . = ALIGN(8);
+    PROVIDE( _data_lma = . );
+  } >ram AT>ram :ram_ro
+
+  .dalign :
+  {
+    . = ALIGN(8);
+    PROVIDE( _data = . );
+  } >ram AT>ram :ram_init
+
+  . = ALIGN(8);
+
+  /* .data, .sdata and .srodata segment */
+  .data :
+  {
+    /* Writable data segment (.data segment) */
+    *(.data .data.*)
+    *(.gnu.linkonce.d.*)
+    /* Have _gp point to middle of sdata/sbss to maximize displacement range */
+    . = ALIGN(8);
+    PROVIDE( _gp = ABSOLUTE(.) + 0x800);
+    /* Writable small data segment (.sdata segment) */
+    *(.sdata .sdata.*)
+    *(.gnu.linkonce.s.*)
+    /* Read-only small data segment (.srodata segment) */
+    . = ALIGN(8);
+    *(.srodata.cst16)
+    *(.srodata.cst8)
+    *(.srodata.cst4)
+    *(.srodata.cst2)
+    *(.srodata .srodata.*)
+    /* Align _edata to cache line size */
+    . = ALIGN(64);
+    PROVIDE( _edata = ABSOLUTE(.) );
+  } >ram AT>ram :ram_init
+
+  /* .bss and .sbss segment */
+  .bss :
+  {
+    PROVIDE( _bss = ABSOLUTE(.) );
+    /* Writable uninitialized small data segment (.sbss segment)*/
+    *(.sbss .sbss.*)
+    *(.gnu.linkonce.sb.*)
+    *(.scommon)
+    /* Uninitialized writeable data section (.bss segment)*/
+    *(.bss .bss.*)
+    *(.gnu.linkonce.b.*)
+    *(COMMON)
+
+    . = ALIGN(8);
+    PROVIDE( _ebss = ABSOLUTE(.) );
+  } >ram AT>ram :ram
+
+  PROVIDE( _tls_data = ABSOLUTE(.) );
+  /*
+   * Thread Local Storage (TLS) are per-thread global variables.
+   * Compilers such as GCC provide a __thread keyword to mark global
+   * variables as per-thread. Support is required in the program loader
+   * and thread creator.
+   */
+
+  /* Thread-local data segment, .tdata (initialized tls). */
+  .tdata :
+  {
+    KEEP( *(.tdata.begin) )
+    *(.tdata .tdata.*)
+    *(.gnu.linkonce.td.*)
+    KEEP( *(.tdata.end) )
+  } >ram AT>ram :ram
+
+  /* Thread-local bss segment, .tbss (zero-initialized tls). */
+  .tbss :
+  {
+    *(.tbss .tbss.*)
+    *(.gnu.linkonce.tb.*)
+    KEEP( *(.tbss.end) )
+  } >ram AT>ram :ram
+
+  /*
+   * End of uninitalized data segement
+   *
+   * Actually the stack needs 16B alignment, and it won't hurt to also slightly
+   * increase the alignment to 32 or even 64 (cache line size).
+   *
+   * Align _heap_start to cache line size
+   */
+  . = ALIGN(64);
+  PROVIDE( _end = ABSOLUTE(.) );
+  /* Leave 2 holes for stack & TLS, the size can set in kconfig */
+  PROVIDE( _heap_start = ABSOLUTE(.) + _stack_size * 2 );
+  PROVIDE( _tp0 = (_end + 63) & (-64) );
+  PROVIDE( _tp1 = _tp0 + _stack_size );
+  PROVIDE( _sp0 = _tp0 + _stack_size );
+  PROVIDE( _sp1 = _tp1 + _stack_size );
+  /* Heap end is at the end of memory, the memory size can set in kconfig */
+  PROVIDE( _heap_end = _ram_end );
+}
+

+ 33 - 0
lib/CMakeLists.txt

@@ -0,0 +1,33 @@
+#project(maix_drivers)
+
+# create driver library
+
+FILE(GLOB_RECURSE LIB_SRC
+        "${CMAKE_CURRENT_LIST_DIR}/*.h"
+        "${CMAKE_CURRENT_LIST_DIR}/*.hpp"
+        "${CMAKE_CURRENT_LIST_DIR}/*.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/*.c"
+        "${CMAKE_CURRENT_LIST_DIR}/*.s"
+        "${CMAKE_CURRENT_LIST_DIR}/*.S"
+        )
+
+FILE(GLOB_RECURSE ASSEMBLY_FILES
+        "${CMAKE_CURRENT_LIST_DIR}/*.s"
+        "${CMAKE_CURRENT_LIST_DIR}/*.S"
+        )
+
+include_directories(${CMAKE_CURRENT_LIST_DIR}/drivers/include ${CMAKE_CURRENT_LIST_DIR}/bsp/include ${CMAKE_CURRENT_LIST_DIR}/firmware/include)
+#
+#HEADER_DIRECTORIES(LIB_HEADERS)
+#
+#INCLUDE_DIRECTORIES(${LIB_HEADERS})
+
+SET_PROPERTY(SOURCE ${ASSEMBLY_FILES} PROPERTY LANGUAGE C)
+SET_SOURCE_FILES_PROPERTIES(${ASSEMBLY_FILES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D __riscv64")
+
+#MESSAGE("CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}")
+
+ADD_LIBRARY(kendryte
+        ${LIB_SRC}
+        )
+SET_TARGET_PROPERTIES(kendryte PROPERTIES LINKER_LANGUAGE C)

+ 29 - 0
lib/bsp/config/fpioa_cfg.c

@@ -0,0 +1,29 @@
+/* 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.
+ */
+
+
+#include "fpioa_cfg.h"
+
+const fpioa_cfg_t g_fpioa_cfg =
+{
+    .version = 1,
+    .io_count = FPIOA_NUM_IO,
+    .io_functions =
+    {
+            [0] = FUNC_JTAG_TCLK,
+
+    }
+};
+

+ 42 - 0
lib/bsp/config/fpioa_cfg.h

@@ -0,0 +1,42 @@
+/* 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.
+ */
+
+
+#ifndef _FPIOA_CFG_H
+#define _FPIOA_CFG_H
+
+#include <fpioa.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+    uint32_t version;
+    uint32_t io_count;
+    enum fpioa_function_e io_functions[FPIOA_NUM_IO];
+} fpioa_cfg_t;
+
+extern const fpioa_cfg_t g_fpioa_cfg;
+int fpioa_get_io_by_func(enum fpioa_function_e function);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+

+ 296 - 0
lib/bsp/crt.S

@@ -0,0 +1,296 @@
+# 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.
+
+#include "env/encoding.h"
+
+# define LREG ld
+# define SREG sd
+# define LFREG fld
+# define SFREG fsd
+# define REGBYTES 8
+# define STKSHIFT 17
+
+
+.section .text.start, "ax", @progbits
+.globl _start
+_start:
+  j 1f
+  .word 0xdeadbeef
+1:
+  csrw mideleg, 0
+  csrw medeleg, 0
+  csrw mie, 0
+  csrw mip, 0
+  la t0, trap_entry
+  csrw mtvec, t0
+
+  li  x1, 0
+  li  x2, 0
+  li  x3, 0
+  li  x4, 0
+  li  x5, 0
+  li  x6, 0
+  li  x7, 0
+  li  x8, 0
+  li  x9, 0
+  li  x10,0
+  li  x11,0
+  li  x12,0
+  li  x13,0
+  li  x14,0
+  li  x15,0
+  li  x16,0
+  li  x17,0
+  li  x18,0
+  li  x19,0
+  li  x20,0
+  li  x21,0
+  li  x22,0
+  li  x23,0
+  li  x24,0
+  li  x25,0
+  li  x26,0
+  li  x27,0
+  li  x28,0
+  li  x29,0
+  li  x30,0
+  li  x31,0
+
+  csrr t0, misa
+  bltz t0, 1f
+  li a0, 1234
+  j sys_exit
+1:
+
+  andi t0, t0, 1 << ('f' - 'a')
+  beqz t0, 1f
+  li t0, MSTATUS_FS
+  csrs mstatus, t0
+
+  fssr    x0
+  fmv.d.x f0, x0
+  fmv.d.x f1, x0
+  fmv.d.x f2, x0
+  fmv.d.x f3, x0
+  fmv.d.x f4, x0
+  fmv.d.x f5, x0
+  fmv.d.x f6, x0
+  fmv.d.x f7, x0
+  fmv.d.x f8, x0
+  fmv.d.x f9, x0
+  fmv.d.x f10,x0
+  fmv.d.x f11,x0
+  fmv.d.x f12,x0
+  fmv.d.x f13,x0
+  fmv.d.x f14,x0
+  fmv.d.x f15,x0
+  fmv.d.x f16,x0
+  fmv.d.x f17,x0
+  fmv.d.x f18,x0
+  fmv.d.x f19,x0
+  fmv.d.x f20,x0
+  fmv.d.x f21,x0
+  fmv.d.x f22,x0
+  fmv.d.x f23,x0
+  fmv.d.x f24,x0
+  fmv.d.x f25,x0
+  fmv.d.x f26,x0
+  fmv.d.x f27,x0
+  fmv.d.x f28,x0
+  fmv.d.x f29,x0
+  fmv.d.x f30,x0
+  fmv.d.x f31,x0
+
+
+1:
+
+  la gp, _gp
+  la  tp, _end + 63
+  and tp, tp, -64
+  csrr a0, mhartid
+  li a1, 2
+
+1:bgeu a0, a1, 1b
+
+  sll a2, a0, STKSHIFT
+  add tp, tp, a2
+  add sp, a0, 1
+  sll sp, sp, STKSHIFT
+  add sp, sp, tp
+
+  j _init_bsp
+
+  .globl trap_entry
+  .type trap_entry, @function
+  .align 2
+trap_entry:
+  addi sp, sp, -64*REGBYTES
+
+  SREG x1, 1*REGBYTES(sp)
+  SREG x2, 2*REGBYTES(sp)
+  SREG x3, 3*REGBYTES(sp)
+  SREG x4, 4*REGBYTES(sp)
+  SREG x5, 5*REGBYTES(sp)
+  SREG x6, 6*REGBYTES(sp)
+  SREG x7, 7*REGBYTES(sp)
+  SREG x8, 8*REGBYTES(sp)
+  SREG x9, 9*REGBYTES(sp)
+  SREG x10, 10*REGBYTES(sp)
+  SREG x11, 11*REGBYTES(sp)
+  SREG x12, 12*REGBYTES(sp)
+  SREG x13, 13*REGBYTES(sp)
+  SREG x14, 14*REGBYTES(sp)
+  SREG x15, 15*REGBYTES(sp)
+  SREG x16, 16*REGBYTES(sp)
+  SREG x17, 17*REGBYTES(sp)
+  SREG x18, 18*REGBYTES(sp)
+  SREG x19, 19*REGBYTES(sp)
+  SREG x20, 20*REGBYTES(sp)
+  SREG x21, 21*REGBYTES(sp)
+  SREG x22, 22*REGBYTES(sp)
+  SREG x23, 23*REGBYTES(sp)
+  SREG x24, 24*REGBYTES(sp)
+  SREG x25, 25*REGBYTES(sp)
+  SREG x26, 26*REGBYTES(sp)
+  SREG x27, 27*REGBYTES(sp)
+  SREG x28, 28*REGBYTES(sp)
+  SREG x29, 29*REGBYTES(sp)
+  SREG x30, 30*REGBYTES(sp)
+  SREG x31, 31*REGBYTES(sp)
+
+  SFREG f0, ( 0  + 32)*REGBYTES(sp)
+  SFREG f1, ( 1  + 32)*REGBYTES(sp)
+  SFREG f2, ( 2  + 32)*REGBYTES(sp)
+  SFREG f3, ( 3  + 32)*REGBYTES(sp)
+  SFREG f4, ( 4  + 32)*REGBYTES(sp)
+  SFREG f5, ( 5  + 32)*REGBYTES(sp)
+  SFREG f6, ( 6  + 32)*REGBYTES(sp)
+  SFREG f7, ( 7  + 32)*REGBYTES(sp)
+  SFREG f8, ( 8  + 32)*REGBYTES(sp)
+  SFREG f9, ( 9  + 32)*REGBYTES(sp)
+  SFREG f10,( 10 + 32)*REGBYTES(sp)
+  SFREG f11,( 11 + 32)*REGBYTES(sp)
+  SFREG f12,( 12 + 32)*REGBYTES(sp)
+  SFREG f13,( 13 + 32)*REGBYTES(sp)
+  SFREG f14,( 14 + 32)*REGBYTES(sp)
+  SFREG f15,( 15 + 32)*REGBYTES(sp)
+  SFREG f16,( 16 + 32)*REGBYTES(sp)
+  SFREG f17,( 17 + 32)*REGBYTES(sp)
+  SFREG f18,( 18 + 32)*REGBYTES(sp)
+  SFREG f19,( 19 + 32)*REGBYTES(sp)
+  SFREG f20,( 20 + 32)*REGBYTES(sp)
+  SFREG f21,( 21 + 32)*REGBYTES(sp)
+  SFREG f22,( 22 + 32)*REGBYTES(sp)
+  SFREG f23,( 23 + 32)*REGBYTES(sp)
+  SFREG f24,( 24 + 32)*REGBYTES(sp)
+  SFREG f25,( 25 + 32)*REGBYTES(sp)
+  SFREG f26,( 26 + 32)*REGBYTES(sp)
+  SFREG f27,( 27 + 32)*REGBYTES(sp)
+  SFREG f28,( 28 + 32)*REGBYTES(sp)
+  SFREG f29,( 29 + 32)*REGBYTES(sp)
+  SFREG f30,( 30 + 32)*REGBYTES(sp)
+  SFREG f31,( 31 + 32)*REGBYTES(sp)
+
+  csrr a0, mcause
+  csrr a1, mepc
+  mv a2, sp
+  add a3, sp, 32*REGBYTES
+  bgez a0, .handle_syscall
+.handle_irq:
+  jal handle_irq
+  j .restore
+.handle_syscall:
+  jal handle_syscall
+.restore:
+  csrw mepc, a0
+  LREG x1, 1*REGBYTES(sp)
+  LREG x2, 2*REGBYTES(sp)
+  LREG x3, 3*REGBYTES(sp)
+  LREG x4, 4*REGBYTES(sp)
+  LREG x5, 5*REGBYTES(sp)
+  LREG x6, 6*REGBYTES(sp)
+  LREG x7, 7*REGBYTES(sp)
+  LREG x8, 8*REGBYTES(sp)
+  LREG x9, 9*REGBYTES(sp)
+  LREG x10, 10*REGBYTES(sp)
+  LREG x11, 11*REGBYTES(sp)
+  LREG x12, 12*REGBYTES(sp)
+  LREG x13, 13*REGBYTES(sp)
+  LREG x14, 14*REGBYTES(sp)
+  LREG x15, 15*REGBYTES(sp)
+  LREG x16, 16*REGBYTES(sp)
+  LREG x17, 17*REGBYTES(sp)
+  LREG x18, 18*REGBYTES(sp)
+  LREG x19, 19*REGBYTES(sp)
+  LREG x20, 20*REGBYTES(sp)
+  LREG x21, 21*REGBYTES(sp)
+  LREG x22, 22*REGBYTES(sp)
+  LREG x23, 23*REGBYTES(sp)
+  LREG x24, 24*REGBYTES(sp)
+  LREG x25, 25*REGBYTES(sp)
+  LREG x26, 26*REGBYTES(sp)
+  LREG x27, 27*REGBYTES(sp)
+  LREG x28, 28*REGBYTES(sp)
+  LREG x29, 29*REGBYTES(sp)
+  LREG x30, 30*REGBYTES(sp)
+  LREG x31, 31*REGBYTES(sp)
+
+  LFREG f0, ( 0  + 32)*REGBYTES(sp)
+  LFREG f1, ( 1  + 32)*REGBYTES(sp)
+  LFREG f2, ( 2  + 32)*REGBYTES(sp)
+  LFREG f3, ( 3  + 32)*REGBYTES(sp)
+  LFREG f4, ( 4  + 32)*REGBYTES(sp)
+  LFREG f5, ( 5  + 32)*REGBYTES(sp)
+  LFREG f6, ( 6  + 32)*REGBYTES(sp)
+  LFREG f7, ( 7  + 32)*REGBYTES(sp)
+  LFREG f8, ( 8  + 32)*REGBYTES(sp)
+  LFREG f9, ( 9  + 32)*REGBYTES(sp)
+  LFREG f10,( 10 + 32)*REGBYTES(sp)
+  LFREG f11,( 11 + 32)*REGBYTES(sp)
+  LFREG f12,( 12 + 32)*REGBYTES(sp)
+  LFREG f13,( 13 + 32)*REGBYTES(sp)
+  LFREG f14,( 14 + 32)*REGBYTES(sp)
+  LFREG f15,( 15 + 32)*REGBYTES(sp)
+  LFREG f16,( 16 + 32)*REGBYTES(sp)
+  LFREG f17,( 17 + 32)*REGBYTES(sp)
+  LFREG f18,( 18 + 32)*REGBYTES(sp)
+  LFREG f19,( 19 + 32)*REGBYTES(sp)
+  LFREG f20,( 20 + 32)*REGBYTES(sp)
+  LFREG f21,( 21 + 32)*REGBYTES(sp)
+  LFREG f22,( 22 + 32)*REGBYTES(sp)
+  LFREG f23,( 23 + 32)*REGBYTES(sp)
+  LFREG f24,( 24 + 32)*REGBYTES(sp)
+  LFREG f25,( 25 + 32)*REGBYTES(sp)
+  LFREG f26,( 26 + 32)*REGBYTES(sp)
+  LFREG f27,( 27 + 32)*REGBYTES(sp)
+  LFREG f28,( 28 + 32)*REGBYTES(sp)
+  LFREG f29,( 29 + 32)*REGBYTES(sp)
+  LFREG f30,( 30 + 32)*REGBYTES(sp)
+  LFREG f31,( 31 + 32)*REGBYTES(sp)
+
+  addi sp, sp, 64*REGBYTES
+  mret
+
+.section ".tdata.begin"
+.globl _tdata_begin
+_tdata_begin:
+
+.section ".tdata.end"
+.globl _tdata_end
+_tdata_end:
+
+.section ".tbss.end"
+.globl _tbss_end
+_tbss_end:
+

+ 37 - 0
lib/bsp/entry.c

@@ -0,0 +1,37 @@
+/* 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.
+ */
+
+#include "entry.h"
+
+/**
+ * @brief      Dummy function for __libc_init_array called
+ */
+void __attribute__((weak)) _init(void)
+{
+    /**
+     * These don't have to do anything since we use init_array/fini_array.
+     */
+}
+
+/**
+ * @brief      Dummy function for __libc_fini_array called
+ */
+void __attribute__((weak)) _fini(void)
+{
+    /**
+     * These don't have to do anything since we use init_array/fini_array.
+     */
+}
+

+ 112 - 0
lib/bsp/entry_user.c

@@ -0,0 +1,112 @@
+/* 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.
+ */
+
+#include <stdlib.h>
+#include "atomic.h"
+#include "clint.h"
+#include "dmac.h"
+#include "entry.h"
+#include "fpioa.h"
+#include "platform.h"
+#include "plic.h"
+#include "sysclock.h"
+#include "sysctl.h"
+#include "syslog.h"
+#include "uarths.h"
+
+volatile char * const ram = (volatile char*)RAM_BASE_ADDR;
+
+extern char _heap_start[];
+extern char _heap_end[];
+
+uint32_t g_wake_up[2] = {1};
+
+void thread_entry(int core_id)
+{
+    /* Clear IPI flag if pending */
+    clint_ipi_clear(core_id);
+    /* Enable software interrupt */
+    clint_ipi_enable();
+    /* Wait for interrupt form core 0 */
+    asm volatile("wfi");
+    atomic_set(&g_wake_up[core_id], 1);
+}
+
+void core_enable(int core_id)
+{
+    clint_ipi_send(core_id);
+    uint32_t cpu_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU);
+    uint32_t old_cycle = read_csr(mcycle);
+    while (!atomic_read(&g_wake_up[core_id]))
+    {
+        if (read_csr(mcycle) - old_cycle > cpu_freq / 1000) /* wait for 1ms */
+        {
+            clint_ipi_send(core_id); /* wakeup again */
+            old_cycle = read_csr(mcycle);
+        }
+    }
+}
+
+int __attribute__((weak)) os_entry(int core_id, int number_of_cores, int (*user_main)(int, char**))
+{
+    /* Call main if there is no OS */
+    return user_main(0, 0);
+}
+
+void _init_bsp(int core_id, int number_of_cores)
+{
+    extern int main(int argc, char* argv[]);
+    extern void __libc_init_array(void);
+    extern void __libc_fini_array(void);
+    /* Initialize thread local data */
+    init_tls();
+
+    if (core_id == 0)
+    {
+        /* Copy lma data to memory */
+        init_lma();
+        /* Initialize bss data to 0 */
+        init_bss();
+        /* Init FPIOA */
+        fpioa_init();
+        /* PLL init */
+        sys_clock_init();
+        /* Init UART */
+        uart_init();
+        /* Dmac init */
+        dmac_init();
+        /* Plic init */
+        plic_init();
+        /* Register finalization function */
+        atexit(__libc_fini_array);
+        /* Init libc array for C++ */
+        __libc_init_array();
+    }
+    else
+    {
+        thread_entry(core_id);
+    }
+
+    if (core_id == 0)
+    {
+        /* Enable Core 1 to run main */
+        core_enable(1);
+    }
+
+    int ret = os_entry(core_id, number_of_cores, main);
+
+    exit(ret);
+}
+

+ 244 - 0
lib/bsp/include/atomic.h

@@ -0,0 +1,244 @@
+
+/* 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.
+ */
+#ifndef _BSP_ATOMIC_H
+#define _BSP_ATOMIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SPINLOCK_INIT \
+    {                 \
+        0             \
+    }
+
+#define HARTLOCK_INIT          \
+    {                          \
+        .lock = SPINLOCK_INIT, \
+        .count = 0,            \
+        .hart = -1             \
+    }
+
+
+/* Defination of memory barrier macro */
+#define mb()                          \
+    {                                 \
+        asm volatile("fence" ::       \
+                         : "memory"); \
+    }
+
+#define atomic_set(ptr, val) (*(volatile typeof(*(ptr))*)(ptr) = val)
+#define atomic_read(ptr) (*(volatile typeof(*(ptr))*)(ptr))
+
+#ifndef __riscv_atomic
+#error "atomic extension is required."
+#endif
+#define atomic_add(ptr, inc) __sync_fetch_and_add(ptr, inc)
+#define atomic_or(ptr, inc) __sync_fetch_and_or(ptr, inc)
+#define atomic_swap(ptr, swp) __sync_lock_test_and_set(ptr, swp)
+#define atomic_cas(ptr, cmp, swp) __sync_val_compare_and_swap(ptr, cmp, swp)
+
+typedef struct
+{
+    int lock;
+} spinlock_t;
+
+typedef struct
+{
+    spinlock_t lock;
+    int count;
+    int waiting;
+} semaphore_t;
+
+
+typedef struct
+{
+    spinlock_t lock;
+    int count;
+    int hart;
+} hartlock_t;
+
+
+static inline int spinlock_trylock(spinlock_t *lock)
+{
+    int res = atomic_swap(&lock->lock, -1);
+    /* Use memory barrier to keep coherency */
+    mb();
+    return res;
+}
+
+static inline void spinlock_lock(spinlock_t *lock)
+{
+    do
+    {
+        while (atomic_read(&lock->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);
+}
+
+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 hartlock_trylock(hartlock_t *lock)
+{
+    int res = 0;
+    unsigned long hart;
+
+    asm volatile("csrr %0, mhartid;"
+                 : "=r"(hart));
+    spinlock_lock(&lock->lock);
+
+    if (lock->count == 0)
+    {
+        /* First time get lock */
+        lock->count++;
+        lock->hart = hart;
+        res = 0;
+    }
+    else if (lock->hart == hart)
+    {
+        /* Same core get lock */
+        lock->count++;
+        res = 0;
+    }
+    else
+    {
+        /* Different core get lock */
+        res = -1;
+    }
+    spinlock_unlock(&lock->lock);
+
+    return res;
+}
+
+static inline void hartlock_lock(hartlock_t *lock)
+{
+    unsigned long hart;
+
+    asm volatile("csrr %0, mhartid;"
+                 : "=r"(hart));
+    spinlock_lock(&lock->lock);
+
+    if (lock->count == 0)
+    {
+        /* First time get lock */
+        lock->count++;
+        lock->hart = hart;
+    }
+    else if (lock->hart == hart)
+    {
+        /* Same core get lock */
+        lock->count++;
+    }
+    else
+    {
+        /* Different core get lock */
+        spinlock_unlock(&lock->lock);
+
+        do
+        {
+            while (atomic_read(&lock->count))
+                ;
+        } while (hartlock_trylock(lock));
+    }
+    spinlock_unlock(&lock->lock);
+}
+
+static inline void hartlock_unlock(hartlock_t *lock)
+{
+    unsigned long hart;
+
+    asm volatile("csrr %0, mhartid;"
+                 : "=r"(hart));
+    spinlock_lock(&lock->lock);
+
+    if (lock->hart == hart)
+    {
+        /* Same core release lock */
+        lock->count--;
+        if (lock->count <= 0)
+        {
+            lock->hart = -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 */
+

+ 141 - 0
lib/bsp/include/dump.h

@@ -0,0 +1,141 @@
+/* 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.
+ */
+
+#ifndef _BSP_DUMP_H
+#define _BSP_DUMP_H
+
+#include <stdlib.h>
+#include <string.h>
+#include "syslog.h"
+#include "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   ", "Thread 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\n", reason);
+        DUMP_PRINTF("Cause 0x%016lx, EPC 0x%016lx\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\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)\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 */
+

+ 71 - 0
lib/bsp/include/entry.h

@@ -0,0 +1,71 @@
+/* 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.
+ */
+
+#ifndef _BSP_ENTRY_H
+#define _BSP_ENTRY_H
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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 init_bss(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 *thread_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(thread_pointer, &_tls_data, tdata_size);
+
+    size_t tbss_size = &_tbss_end - &_tdata_end;
+
+    memset(thread_pointer + tdata_size, 0, tbss_size);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BSP_ENTRY_H */
+

+ 1340 - 0
lib/bsp/include/env/encoding.h

@@ -0,0 +1,1340 @@
+/* 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.
+ */
+
+#ifndef _BSP_ENV_ENCODING_H
+#define _BSP_ENV_ENCODING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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 rdtime() read_csr(time)
+#define rdcycle() read_csr(cycle)
+#define rdinstret() read_csr(instret)
+
+#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
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif    /* _BSP_ENV_ENCODING_H */
+

+ 47 - 0
lib/bsp/include/interrupt.h

@@ -0,0 +1,47 @@
+/* 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.
+ */
+
+#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 */
+

+ 99 - 0
lib/bsp/include/platform.h

@@ -0,0 +1,99 @@
+/* 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.
+ */
+
+#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    (0x38000000U)
+#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 */
+

+ 209 - 0
lib/bsp/include/printf.h

@@ -0,0 +1,209 @@
+/**
+ * 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
+ */
+
+#ifndef _BSP_PRINTF_H
+#define _BSP_PRINTF_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+/* 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 <forward_list>
+namespace std
+{
+    template <typename... Args>
+    auto tfp_printf(Args&&... args) -> decltype(::tfp_printf(std::forward<Args>(args)...))
+    {
+        return ::tfp_printf(std::forward<Args>(args)...);
+    }
+}
+#endif
+#endif
+#endif
+
+int printk(const char *format, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BSP_PRINTF_H */
+

+ 36 - 0
lib/bsp/include/sleep.h

@@ -0,0 +1,36 @@
+/* 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.
+ */
+
+#ifndef _BSP_SLEEP_H
+#define _BSP_SLEEP_H
+
+#include "env/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 */
+

+ 46 - 0
lib/bsp/include/syscalls.h

@@ -0,0 +1,46 @@
+/* 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.
+ */
+
+#ifndef _BSP_SYSCALLS_H
+#define _BSP_SYSCALLS_H
+
+#include <machine/syscall.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#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);
+
+size_t get_free_heap_size(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BSP_SYSCALLS_H */
+

+ 198 - 0
lib/bsp/include/util.h

@@ -0,0 +1,198 @@
+/* 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.
+ */
+
+#ifndef _BSP_UTIL_H
+#define _BSP_UTIL_H
+
+
+#include <stdint.h>
+#if defined(__riscv)
+#include "env/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_csr(mcycle), _i = -read_csr(minstret);                           \
+        code;                                                                                     \
+        _c += read_csr(mcycle), _i += read_csr(minstret);                                         \
+        if (cid == 0)                                                                             \
+            printf("\n%s: %ld cycles, %ld.%ld cycles/iter, %ld.%ld CPI\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 <stdio.h>
+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("\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("\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 */
+

+ 66 - 0
lib/bsp/interrupt.c

@@ -0,0 +1,66 @@
+/* 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.
+ */
+
+/* Enable kernel-mode log API */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include "interrupt.h"
+#include "dump.h"
+#include "syscalls.h"
+#include "syslog.h"
+
+uintptr_t __attribute__((weak))
+handle_irq_dummy(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+    dump_core("unhandled interrupt", cause, epc, regs, fregs);
+    sys_exit(1337);
+    return epc;
+}
+
+uintptr_t __attribute__((weak, alias("handle_irq_dummy")))
+handle_irq_m_soft(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
+
+uintptr_t __attribute__((weak, alias("handle_irq_dummy")))
+handle_irq_m_timer(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
+
+uintptr_t __attribute__((weak, alias("handle_irq_dummy")))
+handle_irq_m_ext(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
+
+uintptr_t __attribute__((weak))
+handle_irq(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Woverride-init"
+#endif
+    /* clang-format off */
+    static uintptr_t (* const irq_table[])(
+        uintptr_t cause,
+        uintptr_t epc,
+        uintptr_t regs[32],
+        uintptr_t fregs[32]) =
+    {
+        [0 ... 14]    = handle_irq_dummy,
+        [IRQ_M_SOFT]  = handle_irq_m_soft,
+        [IRQ_M_TIMER] = handle_irq_m_timer,
+        [IRQ_M_EXT]   = handle_irq_m_ext,
+    };
+	/* clang-format on */
+#if defined(__GNUC__)
+#pragma GCC diagnostic warning "-Woverride-init"
+#endif
+    return irq_table[cause & CAUSE_MACHINE_IRQ_REASON_MASK](cause, epc, regs, fregs);
+}
+

+ 668 - 0
lib/bsp/printf.c

@@ -0,0 +1,668 @@
+/* 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: printf.c
+ *
+ * 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.
+ */
+
+#include <stddef.h>
+#include "printf.h"
+#include "atomic.h"
+#include "uarths.h"
+
+
+/**
+ * Configuration
+ */
+
+/* Enable long int support */
+#define PRINTF_LONG_SUPPORT
+
+/* Enable long long int support (implies long int support) */
+#define PRINTF_LONG_LONG_SUPPORT
+
+/* Enable %z (size_t) support */
+#define PRINTF_SIZE_T_SUPPORT
+
+/**
+ * Configuration adjustments
+ */
+#if defined(PRINTF_LONG_LONG_SUPPORT)
+#define PRINTF_LONG_SUPPORT
+#endif
+
+/* __SIZEOF_<type>__ defined at least by gcc */
+#if defined(__SIZEOF_POINTER__)
+#define SIZEOF_POINTER __SIZEOF_POINTER__
+#endif
+#if defined(__SIZEOF_LONG_LONG__)
+#define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__
+#endif
+#if defined(__SIZEOF_LONG__)
+#define SIZEOF_LONG __SIZEOF_LONG__
+#endif
+#if defined(__SIZEOF_INT__)
+#define SIZEOF_INT __SIZEOF_INT__
+#endif
+
+#if defined(__GNUC__)
+#define _TFP_GCC_NO_INLINE_ __attribute__((noinline))
+#else
+#define _TFP_GCC_NO_INLINE_
+#endif
+
+
+#if defined(PRINTF_LONG_SUPPORT)
+#define BF_MAX 20 /* long = 64b on some architectures */
+#else
+#define BF_MAX 10 /* int = 32b on some architectures */
+#endif
+
+
+#define IS_DIGIT(x) ((x) >= '0' && (x) <= '9')
+
+/* Clear unused warnings for actually unused variables */
+#define UNUSED(x) (void)(x)
+
+
+
+/**
+ * Implementation
+ */
+struct param
+{
+    char lz : 1;         /* Leading zeros */
+    char alt : 1;        /* alternate form */
+    char uc : 1;         /* Upper case (for base16 only) */
+    char align_left : 1; /* 0 == align right (default), 1 == align left */
+    int width;           /* field width */
+    int prec;            /* precision */
+    char sign;           /* The sign to display (if any) */
+    unsigned int base;   /* number base (e.g.: 8, 10, 16) */
+    char *bf;            /* Buffer to output */
+    size_t bf_len;       /* Buffer length */
+};
+
+static hartlock_t lock = HARTLOCK_INIT;
+
+
+
+#if defined(PRINTF_LONG_LONG_SUPPORT)
+static void _TFP_GCC_NO_INLINE_ ulli2a(unsigned long long int num, struct param *p)
+{
+    unsigned long long int d = 1;
+    char *bf = p->bf;
+    if ((p->prec == 0) && (num == 0))
+        return;
+    while (num / d >= p->base)
+    {
+        d *= p->base;
+    }
+    while (d != 0)
+    {
+        int dgt = num / d;
+        num %= d;
+        d /= p->base;
+        *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
+    }
+    p->bf_len = bf - p->bf;
+}
+
+static void lli2a(long long int num, struct param *p)
+{
+    if (num < 0)
+    {
+        num = -num;
+        p->sign = '-';
+    }
+    ulli2a(num, p);
+}
+#endif
+
+#if defined(PRINTF_LONG_SUPPORT)
+static void uli2a(unsigned long int num, struct param *p)
+{
+    unsigned long int d = 1;
+    char *bf = p->bf;
+    if ((p->prec == 0) && (num == 0))
+        return;
+    while (num / d >= p->base)
+    {
+        d *= p->base;
+    }
+    while (d != 0)
+    {
+        int dgt = num / d;
+        num %= d;
+        d /= p->base;
+        *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
+    }
+    p->bf_len = bf - p->bf;
+}
+
+static void li2a(long num, struct param *p)
+{
+    if (num < 0)
+    {
+        num = -num;
+        p->sign = '-';
+    }
+    uli2a(num, p);
+}
+#endif
+
+static void ui2a(unsigned int num, struct param *p)
+{
+    unsigned int d = 1;
+    char *bf = p->bf;
+    if ((p->prec == 0) && (num == 0))
+        return;
+    while (num / d >= p->base)
+    {
+        d *= p->base;
+    }
+    while (d != 0)
+    {
+        int dgt = num / d;
+        num %= d;
+        d /= p->base;
+        *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
+    }
+    p->bf_len = bf - p->bf;
+}
+
+static void i2a(int num, struct param *p)
+{
+    if (num < 0)
+    {
+        num = -num;
+        p->sign = '-';
+    }
+    ui2a(num, p);
+}
+
+static int a2d(char ch)
+{
+    if (IS_DIGIT(ch))
+        return ch - '0';
+    else if (ch >= 'a' && ch <= 'f')
+        return ch - 'a' + 10;
+    else if (ch >= 'A' && ch <= 'F')
+        return ch - 'A' + 10;
+    else
+        return -1;
+}
+
+static char a2u(char ch, const char **src, int base, unsigned int *nump)
+{
+    const char *p = *src;
+    unsigned int num = 0;
+    int digit;
+    while ((digit = a2d(ch)) >= 0)
+    {
+        if (digit > base)
+            break;
+        num = num * base + digit;
+        ch = *p++;
+    }
+    *src = p;
+    *nump = num;
+    return ch;
+}
+
+static void putchw(void *putp, putcf putf, struct param *p)
+{
+    char ch;
+    int width = p->width;
+    int prec = p->prec;
+    char *bf = p->bf;
+    size_t bf_len = p->bf_len;
+
+    /* Number of filling characters */
+    width -= bf_len;
+    prec -= bf_len;
+    if (p->sign)
+        width--;
+    if (p->alt && p->base == 16)
+        width -= 2;
+    else if (p->alt && p->base == 8)
+        width--;
+    if (prec > 0)
+        width -= prec;
+
+    /* Fill with space to align to the right, before alternate or sign */
+    if (!p->lz && !p->align_left)
+    {
+        while (width-- > 0)
+            putf(putp, ' ');
+    }
+
+    /* print sign */
+    if (p->sign)
+        putf(putp, p->sign);
+
+    /* Alternate */
+    if (p->alt && p->base == 16)
+    {
+        putf(putp, '0');
+        putf(putp, (p->uc ? 'X' : 'x'));
+    }
+    else if (p->alt && p->base == 8)
+    {
+        putf(putp, '0');
+    }
+
+    /* Fill with zeros, after alternate or sign */
+    while (prec-- > 0)
+        putf(putp, '0');
+    if (p->lz)
+    {
+        while (width-- > 0)
+            putf(putp, '0');
+    }
+
+    /* Put actual buffer */
+    while ((bf_len-- > 0) && (ch = *bf++))
+        putf(putp, ch);
+
+    /* Fill with space to align to the left, after string */
+    if (!p->lz && p->align_left)
+    {
+        while (width-- > 0)
+            putf(putp, ' ');
+    }
+}
+
+void tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
+{
+    struct param p;
+    char bf[BF_MAX];
+    char ch;
+
+    while ((ch = *(fmt++)))
+    {
+        if (ch != '%')
+        {
+            putf(putp, ch);
+        }
+        else
+        {
+#if defined(PRINTF_LONG_SUPPORT)
+            char lng = 0; /* 1 for long, 2 for long long */
+#endif
+            /* Init parameter struct */
+            p.lz = 0;
+            p.alt = 0;
+            p.uc = 0;
+            p.align_left = 0;
+            p.width = 0;
+            p.prec = -1;
+            p.sign = 0;
+            p.bf = bf;
+            p.bf_len = 0;
+
+            /* Flags */
+            while ((ch = *(fmt++)))
+            {
+                switch (ch)
+                {
+                    case '-':
+                        p.align_left = 1;
+                        continue;
+                    case '0':
+                        p.lz = 1;
+                        continue;
+                    case '#':
+                        p.alt = 1;
+                        continue;
+                    default:
+                        break;
+                }
+                break;
+            }
+
+            if (p.align_left)
+                p.lz = 0;
+
+            /* Width */
+            if (ch == '*')
+            {
+                ch = *(fmt++);
+                p.width = va_arg(va, int);
+                if (p.width < 0)
+                {
+                    p.align_left = 1;
+                    p.width = -p.width;
+                }
+            }
+            else if (IS_DIGIT(ch))
+            {
+                unsigned int width;
+                ch = a2u(ch, &fmt, 10, &(width));
+                p.width = width;
+            }
+
+            /* Precision */
+            if (ch == '.')
+            {
+                ch = *(fmt++);
+                if (ch == '*')
+                {
+                    int prec;
+                    ch = *(fmt++);
+                    prec = va_arg(va, int);
+                    if (prec < 0)
+                        /* act as if precision was
+                         * omitted */
+                        p.prec = -1;
+                    else
+                        p.prec = prec;
+                }
+                else if (IS_DIGIT(ch))
+                {
+                    unsigned int prec;
+                    ch = a2u(ch, &fmt, 10, &(prec));
+                    p.prec = prec;
+                }
+                else
+                {
+                    p.prec = 0;
+                }
+            }
+            if (p.prec >= 0)
+                /* precision causes zero pad to be ignored */
+                p.lz = 0;
+
+#if defined(PRINTF_SIZE_T_SUPPORT)
+#if defined(PRINTF_LONG_SUPPORT)
+            if (ch == 'z')
+            {
+                ch = *(fmt++);
+                if (sizeof(size_t) == sizeof(unsigned long int))
+                    lng = 1;
+#if defined(PRINTF_LONG_LONG_SUPPORT)
+                else if (sizeof(size_t) == sizeof(unsigned long long int))
+                    lng = 2;
+#endif
+            }
+            else
+#endif
+#endif
+
+#if defined(PRINTF_LONG_SUPPORT)
+                if (ch == 'l')
+            {
+                ch = *(fmt++);
+                lng = 1;
+#if defined(PRINTF_LONG_LONG_SUPPORT)
+                if (ch == 'l')
+                {
+                    ch = *(fmt++);
+                    lng = 2;
+                }
+#endif
+            }
+#endif
+            switch (ch)
+            {
+                case 0:
+                    goto abort;
+                case 'u':
+                    p.base = 10;
+                    if (p.prec < 0)
+                        p.prec = 1;
+#if defined(PRINTF_LONG_SUPPORT)
+#if defined(PRINTF_LONG_LONG_SUPPORT)
+                    if (2 == lng)
+                        ulli2a(va_arg(va, unsigned long long int), &p);
+                    else
+#endif
+                        if (1 == lng)
+                        uli2a(va_arg(va, unsigned long int), &p);
+                    else
+#endif
+                        ui2a(va_arg(va, unsigned int), &p);
+                    putchw(putp, putf, &p);
+                    break;
+                case 'd':  /* No break */
+                case 'i':
+                    p.base = 10;
+                    if (p.prec < 0)
+                        p.prec = 1;
+#if defined(PRINTF_LONG_SUPPORT)
+#if defined(PRINTF_LONG_LONG_SUPPORT)
+                    if (2 == lng)
+                        lli2a(va_arg(va, long long int), &p);
+                    else
+#endif
+                        if (1 == lng)
+                        li2a(va_arg(va, long int), &p);
+                    else
+#endif
+                        i2a(va_arg(va, int), &p);
+                    putchw(putp, putf, &p);
+                    break;
+#if defined(SIZEOF_POINTER)
+                case 'p':
+                    p.alt = 1;
+#if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT
+                    lng = 0;
+#elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG
+                    lng = 1;
+#elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG
+                    lng = 2;
+#endif
+#endif
+                    /* No break */
+                case 'x':  /* No break */
+                case 'X':
+                    p.base = 16;
+                    p.uc = (ch == 'X') ? 1 : 0;
+                    if (p.prec < 0)
+                        p.prec = 1;
+#if defined(PRINTF_LONG_SUPPORT)
+#if defined(PRINTF_LONG_LONG_SUPPORT)
+                    if (2 == lng)
+                        ulli2a(va_arg(va, unsigned long long int), &p);
+                    else
+#endif
+                        if (1 == lng)
+                        uli2a(va_arg(va, unsigned long int), &p);
+                    else
+#endif
+                        ui2a(va_arg(va, unsigned int), &p);
+                    putchw(putp, putf, &p);
+                    break;
+                case 'o':
+                    p.base = 8;
+                    if (p.prec < 0)
+                        p.prec = 1;
+                    ui2a(va_arg(va, unsigned int), &p);
+                    putchw(putp, putf, &p);
+                    break;
+                case 'c':
+                    putf(putp, (char)(va_arg(va, int)));
+                    break;
+                case 's':
+                {
+                    unsigned int prec = p.prec;
+                    char *b;
+                    p.bf = va_arg(va, char*);
+                    b = p.bf;
+                    while ((prec-- != 0) && *b++)
+                    {
+                        p.bf_len++;
+                    }
+                    p.prec = -1;
+                    putchw(putp, putf, &p);
+                }
+                break;
+                case '%':
+                    putf(putp, ch);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+abort:;
+}
+
+#if defined(TINYPRINTF_DEFINE_TFP_PRINTF)
+static putcf stdout_putf;
+static void *stdout_putp;
+
+void init_printf(void *putp, putcf putf)
+{
+    stdout_putf = putf;
+    stdout_putp = putp;
+}
+
+void tfp_printf(char *fmt, ...)
+{
+    va_list va;
+    va_start(va, fmt);
+    tfp_format(stdout_putp, stdout_putf, fmt, va);
+    va_end(va);
+}
+#endif
+
+#if defined(TINYPRINTF_DEFINE_TFP_SPRINTF)
+struct _vsnprintf_putcf_data
+{
+    size_t dest_capacity;
+    char *dest;
+    size_t num_chars;
+};
+
+static void _vsnprintf_putcf(void *p, char c)
+{
+    struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p;
+    if (data->num_chars < data->dest_capacity)
+        data->dest[data->num_chars] = c;
+    data->num_chars++;
+}
+
+int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+    struct _vsnprintf_putcf_data data;
+
+    if (size < 1)
+        return 0;
+
+    data.dest = str;
+    data.dest_capacity = size - 1;
+    data.num_chars = 0;
+    tfp_format(&data, _vsnprintf_putcf, format, ap);
+
+    if (data.num_chars < data.dest_capacity)
+        data.dest[data.num_chars] = '\0';
+    else
+        data.dest[data.dest_capacity] = '\0';
+
+    return data.num_chars;
+}
+
+int tfp_snprintf(char *str, size_t size, const char *format, ...)
+{
+    va_list ap;
+    int retval;
+
+    va_start(ap, format);
+    retval = tfp_vsnprintf(str, size, format, ap);
+    va_end(ap);
+    return retval;
+}
+
+struct _vsprintf_putcf_data
+{
+    char *dest;
+    size_t num_chars;
+};
+
+static void _vsprintf_putcf(void *p, char c)
+{
+    struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p;
+    data->dest[data->num_chars++] = c;
+}
+
+int tfp_vsprintf(char *str, const char *format, va_list ap)
+{
+    struct _vsprintf_putcf_data data;
+    data.dest = str;
+    data.num_chars = 0;
+    tfp_format(&data, _vsprintf_putcf, format, ap);
+    data.dest[data.num_chars] = '\0';
+    return data.num_chars;
+}
+
+int tfp_sprintf(char *str, const char *format, ...)
+{
+    va_list ap;
+    int retval;
+
+    va_start(ap, format);
+    retval = tfp_vsprintf(str, format, ap);
+    va_end(ap);
+    return retval;
+}
+#endif
+
+static void uart_putf(void *unused, char c)
+{
+    UNUSED(unused);
+    uart_putchar(c);
+}
+
+int printk(const char *format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    /* Begin protected code */
+    hartlock_lock(&lock);
+    tfp_format(stdout_putp, uart_putf, format, ap);
+    /* End protected code */
+    hartlock_unlock(&lock);
+    va_end(ap);
+
+    return 0;
+}
+

+ 38 - 0
lib/bsp/sleep.c

@@ -0,0 +1,38 @@
+/* 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.
+ */
+#include "sleep.h"
+#include "sysctl.h"
+
+int usleep(uint64_t usec)
+{
+    uint64_t nop_all = usec * sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / 1000000UL / 6;
+
+    while (nop_all--)
+    {
+        asm volatile("nop");
+    }
+    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);
+}
+

+ 641 - 0
lib/bsp/syscalls.c

@@ -0,0 +1,641 @@
+/* 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.
+ */
+
+/* Enable kernel-mode log API */
+
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/unistd.h>
+#include <machine/syscall.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "syscalls.h"
+#include "atomic.h"
+#include "clint.h"
+#include "fpioa.h"
+#include "interrupt.h"
+#include "sysctl.h"
+#include "uarths.h"
+#include "util.h"
+#include "syslog.h"
+#include "dump.h"
+
+/**
+ * @note       System call list
+ *
+ * See also riscv-newlib/libgloss/riscv/syscalls.c
+ *
+ * | System call      | Number |
+ * |------------------|--------|
+ * | SYS_exit         | 93     |
+ * | SYS_exit_group   | 94     |
+ * | SYS_getpid       | 172    |
+ * | SYS_kill         | 129    |
+ * | SYS_read         | 63     |
+ * | SYS_write        | 64     |
+ * | SYS_open         | 1024   |
+ * | SYS_openat       | 56     |
+ * | SYS_close        | 57     |
+ * | SYS_lseek        | 62     |
+ * | SYS_brk          | 214    |
+ * | SYS_link         | 1025   |
+ * | SYS_unlink       | 1026   |
+ * | SYS_mkdir        | 1030   |
+ * | SYS_chdir        | 49     |
+ * | SYS_getcwd       | 17     |
+ * | SYS_stat         | 1038   |
+ * | SYS_fstat        | 80     |
+ * | SYS_lstat        | 1039   |
+ * | SYS_fstatat      | 79     |
+ * | SYS_access       | 1033   |
+ * | SYS_faccessat    | 48     |
+ * | SYS_pread        | 67     |
+ * | SYS_pwrite       | 68     |
+ * | SYS_uname        | 160    |
+ * | SYS_getuid       | 174    |
+ * | SYS_geteuid      | 175    |
+ * | SYS_getgid       | 176    |
+ * | SYS_getegid      | 177    |
+ * | SYS_mmap         | 222    |
+ * | SYS_munmap       | 215    |
+ * | SYS_mremap       | 216    |
+ * | SYS_time         | 1062   |
+ * | SYS_getmainvars  | 2011   |
+ * | SYS_rt_sigaction | 134    |
+ * | SYS_writev       | 66     |
+ * | SYS_gettimeofday | 169    |
+ * | SYS_times        | 153    |
+ * | SYS_fcntl        | 25     |
+ * | SYS_getdents     | 61     |
+ * | SYS_dup          | 23     |
+ *
+ */
+
+#ifndef UNUSED
+#define UNUSED(x) (void)(x)
+#endif
+
+static const char *TAG = "SYSCALL";
+
+extern char _heap_start[];
+extern char _heap_end[];
+char *_heap_cur = &_heap_start[0];
+
+
+void __attribute__((noreturn)) sys_exit(int code)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* First print some diagnostic information. */
+    LOGW(TAG, "sys_exit called by core %ld with 0x%lx\n", hart_id, (uint64_t)code);
+    /* Write exit register to pause netlist simulation */
+    volatile uint32_t *reg = (volatile uint32_t *)0x50440080UL;
+    /* Write stop bit and write back */
+    *reg = (1UL << 31);
+
+    /* Send 0 to uart */
+    uart_putchar(0);
+
+    while (1)
+        continue;
+}
+
+static int sys_nosys(long a0, long a1, long a2, long a3, long a4, long a5, unsigned long n)
+{
+    UNUSED(a3);
+    UNUSED(a4);
+    UNUSED(a5);
+
+    LOGE(TAG, "Unsupported syscall %ld: a0=%lx, a1=%lx, a2=%lx!\n", n, a0, a1, a2);
+    /* Send 0 to uart */
+    uart_putchar(0);
+    while (1)
+        continue;
+    return -ENOSYS;
+}
+
+static int sys_success(void)
+{
+    return 0;
+}
+
+static size_t sys_brk(size_t pos)
+{
+    uintptr_t res = 0;
+    /**
+     * brk() sets the end of the data segment to the value
+     * specified by addr, when that value is reasonable, the system
+     * has enough memory, and the process does not exceed its
+     * maximum data size.
+     *
+     * sbrk() increments the program's data space by increment
+     * bytes. Calling sbrk() with an increment of 0 can be used to
+     * find the current location of the program break.
+     *
+     * uintptr_t brk(uintptr_t ptr);
+     *
+     * IN : regs[10] = ptr
+     * OUT: regs[10] = ptr
+     */
+
+    /**
+     * First call: Initialization brk pointer. newlib will pass
+     * ptr = 0 when it is first called. In this case the address
+     * _heap_start will be return.
+     *
+     * Call again: Adjust brk pointer. The ptr never equal with
+     * 0. If ptr is below _heap_end, then allocate memory.
+     * Otherwise throw out of memory error, return -1.
+     */
+
+    if (pos)
+    {
+        /* Call again */
+        if ((uintptr_t)pos > (uintptr_t)&_heap_end[0])
+        {
+            /* Memory out, return -ENOMEM */
+            LOGE(TAG, "Out of memory\n");
+            res = -ENOMEM;
+        }
+        else
+        {
+            /* Adjust brk pointer. */
+            _heap_cur = (char *)(uintptr_t)pos;
+            /* Return current address. */
+            res = (uintptr_t)_heap_cur;
+        }
+    }
+    else
+    {
+        /* First call, return initial address */
+        res = (uintptr_t)&_heap_start[0];
+    }
+    return (size_t)res;
+}
+
+static ssize_t sys_write(int file, const void *ptr, size_t len)
+{
+    ssize_t res = -EBADF;
+
+    /**
+     * Write to a file.
+     *
+     * ssize_t write(int file, const void* ptr, size_t len)
+     *
+     * IN : regs[10] = file, regs[11] = ptr, regs[12] = len
+     * OUT: regs[10] = len
+     */
+
+    /* Get size to write */
+    register size_t length = len;
+    /* Get data pointer */
+    register char *data = (char *)ptr;
+
+    if (STDOUT_FILENO == file || STDERR_FILENO == file)
+    {
+        /* Write data */
+        while (length-- > 0 && *data != 0)
+            uart_putchar(*(data++));
+
+        /* Return the actual size written */
+        res = len;
+    }
+    else
+    {
+        /* Not support yet */
+        res = -ENOSYS;
+    }
+
+    return res;
+}
+
+static int sys_fstat(int file, struct stat *st)
+{
+    int res = -EBADF;
+
+    /**
+     * Status of an open file. The sys/stat.h header file required
+     * is
+     * distributed in the include subdirectory for this C library.
+     *
+     * int fstat(int file, struct stat* st)
+     *
+     * IN : regs[10] = file, regs[11] = st
+     * OUT: regs[10] = Upon successful completion, 0 shall be
+     * returned.
+     * Otherwise, -1 shall be returned and errno set to indicate
+     * the error.
+     */
+
+    UNUSED(file);
+
+    if (st != NULL)
+        memset(st, 0, sizeof(struct stat));
+    /* Return the result */
+    res = -ENOSYS;
+    /**
+     * Note: This value will return to syscall wrapper, syscall
+     * wrapper will set errno to ENOSYS and return -1
+     */
+
+    return res;
+}
+
+static int sys_close(int file)
+{
+    int res = -EBADF;
+
+    /**
+     * Close a file.
+     *
+     * int close(int file)
+     *
+     * IN : regs[10] = file
+     * OUT: regs[10] = Upon successful completion, 0 shall be
+     * returned.
+     * Otherwise, -1 shall be returned and errno set to indicate
+     * the error.
+     */
+
+    UNUSED(file);
+    /* Return the result */
+    res = 0;
+    return res;
+}
+
+static int sys_gettimeofday(struct timeval *tp, void *tzp)
+{
+    /**
+     * Get the current time.  Only relatively correct.
+     *
+     * int gettimeofday(struct timeval* tp, void* tzp)
+     *
+     * IN : regs[10] = tp
+     * OUT: regs[10] = Upon successful completion, 0 shall be
+     * returned.
+     * Otherwise, -1 shall be returned and errno set to indicate
+     * the error.
+     */
+    UNUSED(tzp);
+
+    if (tp != NULL)
+    {
+        uint64_t clint_usec = clint->mtime / (sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV / 1000000UL);
+
+        tp->tv_sec  = clint_usec / 1000000UL;
+        tp->tv_usec = clint_usec % 1000000UL;
+    }
+    /* Return the result */
+    return 0;
+}
+
+uintptr_t __attribute__((weak))
+handle_ecall(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+    UNUSED(cause);
+    UNUSED(fregs);
+    enum syscall_id_e
+    {
+        SYS_ID_NOSYS,
+        SYS_ID_SUCCESS,
+        SYS_ID_EXIT,
+        SYS_ID_BRK,
+        SYS_ID_WRITE,
+        SYS_ID_FSTAT,
+        SYS_ID_CLOSE,
+        SYS_ID_GETTIMEOFDAY,
+        SYS_ID_MAX
+    };
+
+    static uintptr_t (* const syscall_table[])(long a0, long a1, long a2, long a3, long a4, long a5, unsigned long n) =
+    {
+        [SYS_ID_NOSYS]         = (void *)sys_nosys,
+        [SYS_ID_SUCCESS]       = (void *)sys_success,
+        [SYS_ID_EXIT]          = (void *)sys_exit,
+        [SYS_ID_BRK]           = (void *)sys_brk,
+        [SYS_ID_WRITE]         = (void *)sys_write,
+        [SYS_ID_FSTAT]         = (void *)sys_fstat,
+        [SYS_ID_CLOSE]         = (void *)sys_close,
+        [SYS_ID_GETTIMEOFDAY]  = (void *)sys_gettimeofday,
+    };
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Woverride-init"
+#endif
+    static const uint8_t syscall_id_table[0x100] =
+    {
+        [0x00 ... 0xFF]            = SYS_ID_NOSYS,
+        [0xFF & SYS_exit]          = SYS_ID_EXIT,
+        [0xFF & SYS_exit_group]    = SYS_ID_EXIT,
+        [0xFF & SYS_getpid]        = SYS_ID_NOSYS,
+        [0xFF & SYS_kill]          = SYS_ID_NOSYS,
+        [0xFF & SYS_read]          = SYS_ID_NOSYS,
+        [0xFF & SYS_write]         = SYS_ID_WRITE,
+        [0xFF & SYS_open]          = SYS_ID_NOSYS,
+        [0xFF & SYS_openat]        = SYS_ID_NOSYS,
+        [0xFF & SYS_close]         = SYS_ID_CLOSE,
+        [0xFF & SYS_lseek]         = SYS_ID_NOSYS,
+        [0xFF & SYS_brk]           = SYS_ID_BRK,
+        [0xFF & SYS_link]          = SYS_ID_NOSYS,
+        [0xFF & SYS_unlink]        = SYS_ID_NOSYS,
+        [0xFF & SYS_mkdir]         = SYS_ID_NOSYS,
+        [0xFF & SYS_chdir]         = SYS_ID_NOSYS,
+        [0xFF & SYS_getcwd]        = SYS_ID_NOSYS,
+        [0xFF & SYS_stat]          = SYS_ID_NOSYS,
+        [0xFF & SYS_fstat]         = SYS_ID_FSTAT,
+        [0xFF & SYS_lstat]         = SYS_ID_NOSYS,
+        [0xFF & SYS_fstatat]       = SYS_ID_NOSYS,
+        [0xFF & SYS_access]        = SYS_ID_NOSYS,
+        [0xFF & SYS_faccessat]     = SYS_ID_NOSYS,
+        [0xFF & SYS_pread]         = SYS_ID_NOSYS,
+        [0xFF & SYS_pwrite]        = SYS_ID_NOSYS,
+        [0xFF & SYS_uname]         = SYS_ID_NOSYS,
+        [0xFF & SYS_getuid]        = SYS_ID_NOSYS,
+        [0xFF & SYS_geteuid]       = SYS_ID_NOSYS,
+        [0xFF & SYS_getgid]        = SYS_ID_NOSYS,
+        [0xFF & SYS_getegid]       = SYS_ID_NOSYS,
+        [0xFF & SYS_mmap]          = SYS_ID_NOSYS,
+        [0xFF & SYS_munmap]        = SYS_ID_NOSYS,
+        [0xFF & SYS_mremap]        = SYS_ID_NOSYS,
+        [0xFF & SYS_time]          = SYS_ID_NOSYS,
+        [0xFF & SYS_getmainvars]   = SYS_ID_NOSYS,
+        [0xFF & SYS_rt_sigaction]  = SYS_ID_NOSYS,
+        [0xFF & SYS_writev]        = SYS_ID_NOSYS,
+        [0xFF & SYS_gettimeofday]  = SYS_ID_GETTIMEOFDAY,
+        [0xFF & SYS_times]         = SYS_ID_NOSYS,
+        [0xFF & SYS_fcntl]         = SYS_ID_NOSYS,
+        [0xFF & SYS_getdents]      = SYS_ID_NOSYS,
+        [0xFF & SYS_dup]           = SYS_ID_NOSYS,
+    };
+#if defined(__GNUC__)
+#pragma GCC diagnostic warning "-Woverride-init"
+#endif
+
+    regs[10] = syscall_table[syscall_id_table[0xFF & regs[17]]]
+    (
+        regs[10], /* a0 */
+        regs[11], /* a1 */
+        regs[12], /* a2 */
+        regs[13], /* a3 */
+        regs[14], /* a4 */
+        regs[15], /* a5 */
+        regs[17]  /* n */
+    );
+
+    return epc + ((*(unsigned short *)epc & 3) == 3 ? 4 : 2);
+}
+
+uintptr_t __attribute__((weak, alias("handle_ecall")))
+handle_ecall_u(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
+
+uintptr_t __attribute__((weak, alias("handle_ecall")))
+handle_ecall_h(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
+
+uintptr_t __attribute__((weak, alias("handle_ecall")))
+handle_ecall_s(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
+
+uintptr_t __attribute__((weak, alias("handle_ecall")))
+handle_ecall_m(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]);
+
+uintptr_t __attribute__((weak))
+handle_misaligned_fetch(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+    dump_core("misaligned fetch", cause, epc, regs, fregs);
+    sys_exit(1337);
+    return epc;
+}
+
+uintptr_t __attribute__((weak))
+handle_fault_fetch(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+    dump_core("fault fetch", cause, epc, regs, fregs);
+    sys_exit(1337);
+    return epc;
+}
+
+uintptr_t __attribute__((weak))
+handle_illegal_instruction(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+    dump_core("illegal instruction", cause, epc, regs, fregs);
+    sys_exit(1337);
+    return epc;
+}
+
+uintptr_t __attribute__((weak))
+handle_breakpoint(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+    dump_core("breakpoint", cause, epc, regs, fregs);
+    sys_exit(1337);
+    return epc;
+}
+
+uintptr_t __attribute__((weak))
+handle_misaligned_load(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+    /* notice this function only support 16bit or 32bit instruction */
+
+    bool compressed = (*(unsigned short *)epc & 3) != 3;
+    bool fpu = 0;          /* load to fpu ? */
+    uintptr_t addr = 0;    /* src addr */
+    uint8_t src = 0;       /* src register */
+    uint8_t dst = 0;       /* dst register */
+    uint8_t len = 0;       /* data length */
+    int offset = 0;        /* addr offset to addr in reg */
+    bool unsigned_ = 0;    /* unsigned */
+    uint64_t data_load = 0;/* real data load */
+
+    if (compressed)
+    {
+        /* compressed instruction should not get this fault. */
+        goto on_error;
+    }
+    else
+    {
+        uint32_t instruct = *(uint32_t *)epc;
+        uint8_t opcode = instruct&0x7F;
+
+        dst = (instruct >> 7)&0x1F;
+        len = (instruct >> 12)&3;
+        unsigned_ = (instruct >> 14)&1;
+        src = (instruct >> 15)&0x1F;
+        offset = (instruct >> 20);
+        len = 1 << len;
+        switch (opcode)
+        {
+            case 3:/* load */
+                break;
+            case 7:/* fpu load */
+                fpu = 1;
+                break;
+            default:
+                goto on_error;
+        }
+    }
+
+    if (offset >> 11)
+        offset = -((offset & 0x3FF) + 1);
+
+    addr = (uint64_t)((uint64_t)regs[src] + offset);
+
+    for (int i = 0; i < len; ++i)
+        data_load |= ((uint64_t)*((uint8_t *)addr + i)) << (8 * i);
+
+
+    if (!unsigned_ & !fpu)
+    {
+        /* adjust sign */
+        switch (len)
+        {
+            case 1:
+                data_load = (uint64_t)(int64_t)((int8_t)data_load);
+                break;
+            case 2:
+                data_load = (uint64_t)(int64_t)((int16_t)data_load);
+                break;
+            case 4:
+                data_load = (uint64_t)(int64_t)((int32_t)data_load);
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (fpu)
+        fregs[dst] = data_load;
+    else
+        regs[dst] = data_load;
+
+    LOGV(TAG, "misaligned load recovered at %08lx. len:%02d,addr:%08lx,reg:%02d,data:%016lx,signed:%1d,float:%1d", (uint64_t)epc, len, (uint64_t)addr, dst, data_load, !unsigned_, fpu);
+
+    return epc + (compressed ? 2 : 4);
+on_error:
+    dump_core("misaligned load", cause, epc, regs, fregs);
+    sys_exit(1337);
+    return epc;
+}
+
+uintptr_t __attribute__((weak))
+handle_fault_load(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+    dump_core("fault load", cause, epc, regs, fregs);
+    sys_exit(1337);
+    return epc;
+}
+
+uintptr_t __attribute__((weak))
+handle_misaligned_store(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+    /* notice this function only support 16bit or 32bit instruction */
+
+    bool compressed = (*(unsigned short *)epc & 3) != 3;
+    bool fpu = 0;           /* store to fpu*/
+    uintptr_t addr = 0;     /* src addr*/
+    uint8_t src = 0;        /* src register*/
+    uint8_t dst = 0;        /* dst register*/
+    uint8_t len = 0;        /* data length*/
+    int offset = 0;         /* addr offset to addr in reg*/
+    uint64_t data_store = 0;/* real data store*/
+
+    if (compressed)
+    {
+        /* compressed instruction should not get this fault. */
+        goto on_error;
+    }
+    else
+    {
+        uint32_t instruct = *(uint32_t *)epc;
+        uint8_t opcode = instruct&0x7F;
+
+        len = (instruct >> 12)&7;
+        dst = (instruct >> 15)&0x1F;
+        src = (instruct >> 20)&0x1F;
+        offset = ((instruct >> 7)&0x1F) | ((instruct >> 20)&0xFE0);
+        len = 1 << len;
+        switch (opcode)
+        {
+            case 0x23:/* store */
+                break;
+            case 0x27:/* fpu store */
+                fpu = 1;
+                break;
+            default:
+                goto on_error;
+        }
+    }
+
+    if (offset >> 11)
+        offset = -((offset & 0x3FF) + 1);
+
+    addr = (uint64_t)((uint64_t)regs[dst] + offset);
+
+
+    if (fpu)
+        data_store = fregs[src];
+    else
+        data_store = regs[src];
+
+    for (int i = 0; i < len; ++i)
+        *((uint8_t *)addr + i) = (data_store >> (i*8)) & 0xFF;
+
+    LOGV(TAG, "misaligned store recovered at %08lx. len:%02d,addr:%08lx,reg:%02d,data:%016lx,float:%1d", (uint64_t)epc, len, (uint64_t)addr, src, data_store, fpu);
+
+    return epc + (compressed ? 2 : 4);
+on_error:
+    dump_core("misaligned store", cause, epc, regs, fregs);
+    sys_exit(1337);
+    return epc;
+}
+
+uintptr_t __attribute__((weak))
+handle_fault_store(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+    dump_core("fault store", cause, epc, regs, fregs);
+    sys_exit(1337);
+    return epc;
+}
+
+uintptr_t handle_syscall(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
+{
+
+    static uintptr_t (* const cause_table[])(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) =
+    {
+        [CAUSE_MISALIGNED_FETCH]      = handle_misaligned_fetch,
+        [CAUSE_FAULT_FETCH]           = handle_fault_fetch,
+        [CAUSE_ILLEGAL_INSTRUCTION]   = handle_illegal_instruction,
+        [CAUSE_BREAKPOINT]            = handle_breakpoint,
+        [CAUSE_MISALIGNED_LOAD]       = handle_misaligned_load,
+        [CAUSE_FAULT_LOAD]            = handle_fault_load,
+        [CAUSE_MISALIGNED_STORE]      = handle_misaligned_store,
+        [CAUSE_FAULT_STORE]           = handle_fault_store,
+        [CAUSE_USER_ECALL]            = handle_ecall_u,
+        [CAUSE_SUPERVISOR_ECALL]      = handle_ecall_h,
+        [CAUSE_HYPERVISOR_ECALL]      = handle_ecall_s,
+        [CAUSE_MACHINE_ECALL]         = handle_ecall_m,
+    };
+
+    return cause_table[cause](cause, epc, regs, fregs);
+}
+
+size_t get_free_heap_size(void)
+{
+    return (size_t)(&_heap_end[0] - _heap_cur);
+}
+

+ 365 - 0
lib/drivers/aes.c

@@ -0,0 +1,365 @@
+/* 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.
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include "env/encoding.h"
+#include "aes.h"
+#include "sysctl.h"
+
+volatile aes_t* const aes = (volatile aes_t*)AES_BASE_ADDR;
+
+void aes_clkinit()
+{
+    sysctl_clock_enable(SYSCTL_CLOCK_AES);
+    sysctl_reset(SYSCTL_RESET_AES);
+}
+
+int aes_init(uint8_t* key_addr, uint8_t key_length, uint8_t* aes_iv,
+    uint8_t iv_length, uint8_t* aes_aad, enum aes_cipher_mod cipher_mod,
+    enum aes_encrypt_sel encrypt_sel, uint32_t add_size, uint32_t data_size)
+{
+    int i, remainder, num, cnt;
+    uint32_t u32data;
+    uint8_t u8data[4] = {0};
+
+    if ((cipher_mod == AES_ECB) || (cipher_mod == AES_CBC))
+        data_size = ((data_size + 15) / 16) * 16;
+    aes->aes_endian |= 1;
+
+    /* write key Low byte alignment*/
+    num = key_length / 4;
+    for (i = 0; i < num; i++)
+        aes->aes_key[i] = *((uint32_t*)(&key_addr[key_length - (4 * i) - 4]));
+    remainder = key_length % 4;
+    if (remainder)
+    {
+        switch (remainder)
+        {
+        case 1:
+            u8data[0] = key_addr[0];
+            break;
+        case 2:
+            u8data[0] = key_addr[0];
+            u8data[1] = key_addr[1];
+            break;
+        case 3:
+            u8data[0] = key_addr[0];
+            u8data[1] = key_addr[1];
+            u8data[2] = key_addr[2];
+            break;
+        default:
+            break;
+        }
+        aes->aes_key[num] = *((uint32_t*)(&u8data[0]));
+    }
+
+    /*write iv Low byte alignment*/
+    num = iv_length / 4;
+    for (i = 0; i < num; i++)
+        aes->aes_iv[i] = *((uint32_t*)(&aes_iv[iv_length - (4 * i) - 4]));
+    remainder = iv_length % 4;
+    if (remainder)
+    {
+        switch (remainder)
+        {
+        case 1:
+            u8data[0] = aes_iv[0];
+            break;
+        case 2:
+            u8data[0] = aes_iv[0];
+            u8data[1] = aes_iv[1];
+            break;
+        case 3:
+            u8data[0] = aes_iv[0];
+            u8data[1] = aes_iv[1];
+            u8data[2] = aes_iv[2];
+            break;
+        default:
+            break;
+        }
+        aes->aes_iv[num] = *((uint32_t*)(&u8data[0]));
+    }
+
+    aes->mode_ctl.cipher_mode = cipher_mod;
+
+    /*
+     * [1:0],set the first bit and second bit 00:ecb; 01:cbc;
+     * 10,11:aes_gcm
+     */
+    aes->encrypt_sel = encrypt_sel;
+    aes->gb_aad_end_adr = add_size - 1;
+    aes->gb_pc_end_adr = data_size - 1;
+    aes->gb_aes_en |= 1;
+
+    /* write aad */
+    if (cipher_mod == AES_GCM)
+    {
+        num = add_size / 4;
+        for (i = 0; i < num; i++)
+        {
+            u32data = *((uint32_t*)(&aes_aad[i * 4]));
+            while (!aes_get_data_in_flag())
+                ;
+            aes_write_aad(u32data);
+        }
+        cnt = 4 * num;
+        remainder = add_size % 4;
+        if (remainder)
+        {
+            switch (remainder)
+            {
+            case 1:
+                u8data[0] = aes_aad[cnt];
+                break;
+            case 2:
+                u8data[0] = aes_aad[cnt];
+                u8data[1] = aes_aad[cnt + 1];
+                break;
+            case 3:
+                u8data[0] = aes_aad[cnt];
+                u8data[1] = aes_aad[cnt + 1];
+                u8data[2] = aes_aad[cnt + 2];
+                break;
+            default:
+                return 0;
+            }
+            u32data = *((uint32_t*)(&u8data[0]));
+            while (!aes_get_data_in_flag())
+                ;
+            aes_write_aad(u32data);
+        }
+    }
+
+    return 1;
+}
+
+int aes_write_aad(uint32_t aad_data)
+{
+    aes->aes_aad_data = aad_data;
+    return 0;
+}
+
+int aes_write_text(uint32_t text_data)
+{
+    aes->aes_text_data = text_data;
+    return 0;
+}
+
+int aes_write_tag(uint32_t* tag)
+{
+    aes->gcm_in_tag[0] = tag[3];
+    aes->gcm_in_tag[1] = tag[2];
+    aes->gcm_in_tag[2] = tag[1];
+    aes->gcm_in_tag[3] = tag[0];
+    return 0;
+}
+
+int aes_get_data_in_flag(void)
+{
+    /* data can in flag 1: data ready 0: data not ready */
+    return aes->data_in_flag;
+}
+
+int aes_get_data_out_flag(void)
+{
+    /* data can output flag 1: data ready 0: data not ready */
+    return aes->data_out_flag;
+}
+
+int aes_get_tag_in_flag(void)
+{
+    /* data can output flag 1: data ready 0: data not ready */
+    return aes->tag_in_flag;
+}
+
+uint32_t aes_read_out_data(void)
+{
+    return aes->aes_out_data;
+}
+
+int aes_check_tag(void)
+{
+    return aes->tag_chk;
+}
+
+int aes_get_tag(uint8_t* l_tag)
+{
+    uint32_t u32tag;
+    uint8_t i = 0;
+
+    u32tag = aes->gcm_out_tag[3];
+    l_tag[i++] = (uint8_t)((u32tag >> 24) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag >> 16) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag >> 8) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag)&0xff);
+
+    u32tag = aes->gcm_out_tag[2];
+    l_tag[i++] = (uint8_t)((u32tag >> 24) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag >> 16) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag >> 8) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag)&0xff);
+
+    u32tag = aes->gcm_out_tag[1];
+    l_tag[i++] = (uint8_t)((u32tag >> 24) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag >> 16) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag >> 8) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag)&0xff);
+
+    u32tag = aes->gcm_out_tag[0];
+    l_tag[i++] = (uint8_t)((u32tag >> 24) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag >> 16) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag >> 8) & 0xff);
+    l_tag[i++] = (uint8_t)((u32tag)&0xff);
+    return 1;
+}
+
+int aes_clear_chk_tag(void)
+{
+    aes->tag_clear = 0;
+    return 0;
+}
+
+int aes_process_less_80_bytes(uint8_t* aes_in_data,
+    uint8_t* aes_out_data,
+    uint32_t data_size,
+    enum aes_cipher_mod cipher_mod)
+{
+    int padding_size;
+    int num, i, remainder, cnt;
+    uint32_t u32data;
+    uint8_t u8data[4] = {0};
+    /* Fill 128 bits    (16byte) */
+    padding_size = ((data_size + 15) / 16) * 16;
+
+    /* write text */
+    num = data_size / 4;
+    for (i = 0; i < num; i++)
+    {
+        u32data = *((uint32_t*)(&aes_in_data[i * 4]));
+        while (!aes_get_data_in_flag())
+            ;
+        aes_write_text(u32data);
+    }
+    cnt = 4 * num;
+    remainder = data_size % 4;
+    if (remainder)
+    {
+        switch (remainder)
+        {
+        case 1:
+            u8data[0] = aes_in_data[cnt];
+            break;
+        case 2:
+            u8data[0] = aes_in_data[cnt];
+            u8data[1] = aes_in_data[cnt + 1];
+            break;
+        case 3:
+            u8data[0] = aes_in_data[cnt];
+            u8data[1] = aes_in_data[cnt + 1];
+            u8data[2] = aes_in_data[cnt + 2];
+            break;
+        default:
+            return 0;
+        }
+        u32data = *((uint32_t*)(&u8data[0]));
+        while (!aes_get_data_in_flag())
+            ;
+        aes_write_text(u32data);
+    }
+    if ((cipher_mod == AES_ECB) || (cipher_mod == AES_CBC))
+    {
+        /* use 0 to Fill 128 bits */
+        num = (padding_size - data_size) / 4;
+        for (i = 0; i < num; i++)
+        {
+            while (!aes_get_data_in_flag())
+                ;
+            aes_write_text(0);
+        }
+        /* get data */
+        num = padding_size / 4;
+    }
+    /* get data */
+    for (i = 0; i < num; i++)
+    {
+        while (!aes_get_data_out_flag())
+            ;
+        *((uint32_t*)(&aes_out_data[i * 4])) = aes_read_out_data();
+    }
+    if ((cipher_mod == AES_GCM) && (remainder))
+    {
+        while (!aes_get_data_out_flag())
+            ;
+
+        *((uint32_t*)(&u8data[0])) = aes_read_out_data();
+        switch (remainder)
+        {
+        case 1:
+            aes_out_data[num * 4] = u8data[0];
+            break;
+        case 2:
+            aes_out_data[num * 4] = u8data[0];
+            aes_out_data[(i * 4) + 1] = u8data[1];
+            break;
+        case 3:
+            aes_out_data[num * 4] = u8data[0];
+            aes_out_data[(i * 4) + 1] = u8data[1];
+            aes_out_data[(i * 4) + 2] = u8data[2];
+            break;
+        default:
+            return 0;
+        }
+    }
+    return 1;
+}
+
+int aes_process(uint8_t* aes_in_data,
+    uint8_t* aes_out_data,
+    uint32_t data_size,
+    enum aes_cipher_mod cipher_mod)
+{
+    uint32_t i, temp_size;
+
+    i = 0;
+    if (data_size >= 80)
+    {
+        for (i = 0; i < (data_size / 80); i++)
+            aes_process_less_80_bytes(&aes_in_data[i * 80], &aes_out_data[i * 80], 80, cipher_mod);
+    }
+    temp_size = data_size % 80;
+    if (temp_size)
+        aes_process_less_80_bytes(&aes_in_data[i * 80], &aes_out_data[i * 80], temp_size, cipher_mod);
+    return 1;
+}
+
+int aes_check_gcm_tag(uint32_t* aes_gcm_tag)
+{
+    /* check tag */
+    while (!aes_get_tag_in_flag())
+        ;
+    aes_write_tag(aes_gcm_tag);
+    while (!aes_check_tag())
+        ;
+    if (aes_check_tag() == 2)
+    {
+        aes_clear_chk_tag();
+        return 1;
+    }
+    else
+    {
+        aes_clear_chk_tag();
+        return 0;
+    }
+}

+ 441 - 0
lib/drivers/audio_bf.c

@@ -0,0 +1,441 @@
+/* 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.
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include "env/encoding.h"
+#include "audio_bf.h"
+#include "syscalls.h"
+#include "sysctl.h"
+
+#define BEAFORMING_BASE_ADDR (0x50250200U)
+
+volatile struct audio_bf_reg_t* const audio_bf = (volatile struct audio_bf_reg_t*)BEAFORMING_BASE_ADDR;
+
+/**
+ * Voice strength average value right shift factor.  When performing sound direction detect,
+ * the average value of samples from different channels is required, this right shift factor
+ * is used to perform division.
+ * 0x0: no right shift;
+ * 0x1: right shift by 1-bit;
+ *  . . . . . .
+ * 0xF: right shift by 14-bit.
+*/
+void audio_bf_set_audio_gain(uint16_t gain)
+{
+    struct audio_bf_ch_cfg_t ch_cfg = audio_bf->bf_ch_cfg_reg;
+
+    ch_cfg.we_bf_target_dir = 0;
+    ch_cfg.we_bf_sound_ch_en = 0;
+    ch_cfg.we_data_src_mode = 0;
+    ch_cfg.we_audio_gain = 1;
+    ch_cfg.audio_gain = gain;
+    audio_bf->bf_ch_cfg_reg = ch_cfg;
+}
+
+void audio_bf_set_smpl_shift(uint8_t smpl_shift)
+{
+    struct audio_bf_dwsz_cfg_t tmp = audio_bf->bf_dwsz_cfg_reg;
+
+    tmp.smpl_shift_bits = smpl_shift;
+    audio_bf->bf_dwsz_cfg_reg = tmp;
+}
+
+uint8_t audio_bf_get_smpl_shift(void)
+{
+    struct audio_bf_dwsz_cfg_t tmp = audio_bf->bf_dwsz_cfg_reg;
+
+    return tmp.smpl_shift_bits;
+}
+
+/**
+ * BF unit sound channel enable control bits.  Bit 'x' corresponds to enable bit for sound
+ * channel 'x' (x = 0, 1, 2, . . ., 7).  BF sound channels are related with I2S host RX channels.
+ * BF sound channel 0/1 correspond to the left/right channel of I2S RX0; BF channel 2/3 correspond
+ * to left/right channels of I2S RX1; and things like that.  Software write '1' to enable a sound
+ * channel and hardware automatically clear the bit after the sample buffers used for direction
+ * searching is filled full.
+ * 0x1: writing '1' to enable the corresponding BF sound channel.
+ */
+void audio_bf_set_channel_enabled(uint8_t channel_bit)
+{
+    struct audio_bf_ch_cfg_t ch_cfg;
+
+    ch_cfg.we_audio_gain = 0;
+    ch_cfg.we_bf_target_dir = 0;
+    ch_cfg.we_bf_sound_ch_en = 1;
+    ch_cfg.bf_sound_ch_en = channel_bit;
+    audio_bf->bf_ch_cfg_reg = ch_cfg;
+}
+
+/**
+ * BF unit sound channel enable control bits.  Bit 'x' corresponds to enable bit for sound
+ * channel 'x' (x = 0, 1, 2, . . ., 7).  BF sound channels are related with I2S host RX channels.
+ * BF sound channel 0/1 correspond to the left/right channel of I2S RX0; BF channel 2/3 correspond
+ * to left/right channels of I2S RX1; and things like that.  Software write '1' to enable a sound
+ * channel and hardware automatically clear the bit after the sample buffers used for direction
+ * searching is filled full.
+ * 0x1: writing '1' to enable the corresponding BF sound channel.
+ */
+void audio_bf_channel_enable(uint8_t channel_bit)
+{
+    struct audio_bf_ch_cfg_t ch_cfg = audio_bf->bf_ch_cfg_reg;
+
+    ch_cfg.we_audio_gain = 0;
+    ch_cfg.we_bf_target_dir = 0;
+    ch_cfg.we_data_src_mode = 0;
+    ch_cfg.we_bf_sound_ch_en = 1;
+    ch_cfg.bf_sound_ch_en = channel_bit;
+    audio_bf->bf_ch_cfg_reg = ch_cfg;
+}
+
+/**
+ * audio data source configure parameter.  This parameter controls where the audio data source comes from.
+ * 0x0: audio data directly sourcing from audio_bf internal buffer;
+ * 0x1: audio data sourcing from FFT result buffer.
+ */
+void audio_bf_set_src_mode(uint8_t src_mode)
+{
+    struct audio_bf_ch_cfg_t ch_cfg = audio_bf->bf_ch_cfg_reg;
+
+    ch_cfg.we_audio_gain = 0;
+    ch_cfg.we_bf_target_dir = 0;
+    ch_cfg.we_bf_sound_ch_en = 0;
+    ch_cfg.we_data_src_mode = 1;
+    ch_cfg.data_src_mode = src_mode;
+    audio_bf->bf_ch_cfg_reg = ch_cfg;
+}
+
+/**
+ * I2S host beam-forming direction sample ibuffer read index configure register
+ */
+void audio_bf_set_direction_delay(uint8_t dir_num, uint8_t* dir_bidx)
+{
+    audio_bf->bf_dir_bidx[dir_num][0] = (struct audio_bf_dir_bidx_t){
+        .dir_rd_idx0 = dir_bidx[0],
+        .dir_rd_idx1 = dir_bidx[1],
+        .dir_rd_idx2 = dir_bidx[2],
+        .dir_rd_idx3 = dir_bidx[3]};
+    audio_bf->bf_dir_bidx[dir_num][1] = (struct audio_bf_dir_bidx_t){
+        .dir_rd_idx0 = dir_bidx[4],
+        .dir_rd_idx1 = dir_bidx[5],
+        .dir_rd_idx2 = dir_bidx[6],
+        .dir_rd_idx3 = dir_bidx[7]};
+}
+
+/**
+ * Sound direction searching enable bit.  Software writes '1' to start sound direction searching function.
+ * When all the sound sample buffers are filled full, this bit is cleared by hardware (this sample buffers
+ * are used for direction detect only).
+ * 0x1: enable direction searching.
+ */
+void audio_bf_dir_enable(void)
+{
+    struct audio_bf_ctl_t bf_en_tmp = audio_bf->bf_ctl_reg;
+
+    bf_en_tmp.we_bf_dir_search_en = 1;
+    bf_en_tmp.bf_dir_search_en = 1;
+    audio_bf->bf_ctl_reg = bf_en_tmp;
+}
+
+void audio_bf_dir_reset(void)
+{
+    struct audio_bf_ctl_t bf_en_tmp = audio_bf->bf_ctl_reg;
+
+    bf_en_tmp.we_search_path_rst = 1;
+    bf_en_tmp.search_path_reset = 1;
+    audio_bf->bf_ctl_reg = bf_en_tmp;
+}
+
+/**
+ * Valid voice sample stream generation enable bit.  After sound direction searching is done, software can
+ * configure this bit to generate a stream of voice samples for voice recognition.
+ * 0x1: enable output of voice sample stream.
+ * 0x0: stop the voice samlpe stream output.
+ */
+void audio_bf_voc_enable(uint8_t enable_flag)
+{
+    struct audio_bf_ctl_t bf_en_tmp = audio_bf->bf_ctl_reg;
+
+    bf_en_tmp.we_bf_stream_gen = 1;
+    bf_en_tmp.bf_stream_gen_en = enable_flag;
+    audio_bf->bf_ctl_reg = bf_en_tmp;
+}
+
+void audio_bf_voc_reset(void)
+{
+    struct audio_bf_ctl_t bf_en_tmp = audio_bf->bf_ctl_reg;
+
+    bf_en_tmp.we_voice_gen_path_rst = 1;
+    bf_en_tmp.voice_gen_path_reset = 1;
+    audio_bf->bf_ctl_reg = bf_en_tmp;
+}
+
+/**
+ * Target direction select for valid voice output.  When the source voice direaction searching
+ * is done, software can use this field to select one from 16 sound directions for the following
+ * voice recognition
+ * 0x0: select sound direction 0;   0x1: select sound direction 1;
+ *  . . . . . .
+ * 0xF: select sound direction 15.
+*/
+void audio_bf_voc_set_direction(enum en_bf_dir direction)
+{
+    struct audio_bf_ch_cfg_t ch_cfg = audio_bf->bf_ch_cfg_reg;
+
+    ch_cfg.we_bf_sound_ch_en = 0;
+    ch_cfg.we_audio_gain = 0;
+    ch_cfg.we_data_src_mode = 0;
+    ch_cfg.we_bf_target_dir = 1;
+    ch_cfg.bf_target_dir = direction;
+    audio_bf->bf_ch_cfg_reg = ch_cfg;
+
+    struct audio_bf_ctl_t bf_en_tmp = audio_bf->bf_ctl_reg;
+
+    bf_en_tmp.we_update_voice_dir = 1;
+    bf_en_tmp.update_voice_dir = 1;
+    audio_bf->bf_ctl_reg = bf_en_tmp;
+}
+
+/**
+ * I2S host beam-forming Filter FIR16 Coefficient Register
+ */
+void audio_bf_dir_set_prev_fir(uint16_t* fir_coef)
+{
+    uint8_t i = 0;
+
+    for (i = 0; i < 9; i++)
+    {
+        audio_bf->bf_pre_fir0_coef[i] = (struct audio_bf_fir_coef_t){
+            .fir_tap0 = fir_coef[i * 2],
+            .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]};
+    }
+}
+
+void audio_bf_dir_set_post_fir(uint16_t* fir_coef)
+{
+    uint8_t i = 0;
+
+    for (i = 0; i < 9; i++)
+    {
+        audio_bf->bf_post_fir0_coef[i] = (struct audio_bf_fir_coef_t){
+            .fir_tap0 = fir_coef[i * 2],
+            .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]};
+    }
+}
+
+void audio_bf_voc_set_prev_fir(uint16_t* fir_coef)
+{
+    uint8_t i = 0;
+
+    for (i = 0; i < 9; i++)
+    {
+        audio_bf->bf_pre_fir1_coef[i] = (struct audio_bf_fir_coef_t){
+            .fir_tap0 = fir_coef[i * 2],
+            .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]};
+    }
+}
+
+void audio_bf_voc_set_post_fir(uint16_t* fir_coef)
+{
+    uint8_t i = 0;
+
+    for (i = 0; i < 9; i++)
+    {
+        audio_bf->bf_post_fir1_coef[i] = (struct audio_bf_fir_coef_t){
+            .fir_tap0 = fir_coef[i * 2],
+            .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]};
+    }
+}
+
+void audio_bf_set_fft_shift_factor(uint8_t enable_flag, uint16_t shift_factor)
+{
+    audio_bf->bf_fft_cfg_reg = (struct audio_bf_fft_cfg_t){
+        .fft_enable = enable_flag,
+        .fft_shift_factor = shift_factor};
+
+    struct audio_bf_ch_cfg_t ch_cfg = audio_bf->bf_ch_cfg_reg;
+
+    ch_cfg.we_data_src_mode = 1;
+    ch_cfg.data_src_mode = enable_flag;
+    audio_bf->bf_ch_cfg_reg = ch_cfg;
+}
+
+void audio_bf_dir_set_down_size(uint8_t dir_dwn_size)
+{
+    struct audio_bf_dwsz_cfg_t tmp = audio_bf->bf_dwsz_cfg_reg;
+
+    tmp.dir_dwn_siz_rate = dir_dwn_size;
+    audio_bf->bf_dwsz_cfg_reg = tmp;
+}
+
+void audio_bf_dir_set_interrupt_mask(uint8_t dir_int_mask)
+{
+    struct audio_bf_int_mask_t tmp = audio_bf->bf_int_mask_reg;
+
+    tmp.dir_data_rdy_msk = dir_int_mask;
+    audio_bf->bf_int_mask_reg = tmp;
+}
+
+void audio_bf_voc_set_down_size(uint8_t voc_dwn_size)
+{
+    struct audio_bf_dwsz_cfg_t tmp = audio_bf->bf_dwsz_cfg_reg;
+
+    tmp.voc_dwn_siz_rate = voc_dwn_size;
+    audio_bf->bf_dwsz_cfg_reg = tmp;
+}
+
+void audio_bf_voc_set_interrupt_mask(uint8_t voc_int_mask)
+{
+    struct audio_bf_int_mask_t tmp = audio_bf->bf_int_mask_reg;
+
+    tmp.voc_buf_rdy_msk = voc_int_mask;
+    audio_bf->bf_int_mask_reg = tmp;
+}
+
+void audio_bf_set_down_size(uint8_t dir_dwn_size, uint8_t voc_dwn_size)
+{
+    struct audio_bf_dwsz_cfg_t tmp = audio_bf->bf_dwsz_cfg_reg;
+
+    tmp.dir_dwn_siz_rate = dir_dwn_size;
+    tmp.voc_dwn_siz_rate = voc_dwn_size;
+    audio_bf->bf_dwsz_cfg_reg = tmp;
+}
+
+void audio_bf_set_interrupt_mask(uint8_t dir_int_mask, uint8_t voc_int_mask)
+{
+    audio_bf->bf_int_mask_reg = (struct audio_bf_int_mask_t){
+        .dir_data_rdy_msk = dir_int_mask,
+        .voc_buf_rdy_msk = voc_int_mask};
+}
+
+void audio_bf_dir_clear_int_state(void)
+{
+    audio_bf->bf_int_stat_reg = (struct audio_bf_int_stat_t){
+        .dir_search_data_rdy = 1};
+}
+
+void audio_bf_voc_clear_int_state(void)
+{
+    audio_bf->bf_int_stat_reg = (struct audio_bf_int_stat_t){
+        .voc_buf_data_rdy = 1};
+}
+
+void audio_bf_voc_reset_saturation_counter(void)
+{
+    audio_bf->saturation_counter = 1 << 31;
+}
+
+/* heigh 16 bit is counter, low 16 bit is total.*/
+uint32_t audio_bf_voc_get_saturation_counter(void)
+{
+    return audio_bf->saturation_counter;
+}
+
+void audio_bf_voc_set_saturation_limit(uint16_t upper, uint16_t bottom)
+{
+    audio_bf->saturation_limits = (uint32_t)bottom << 16 | upper;
+}
+
+/* heigh 16 bit is counter, low 16 bit is total.*/
+uint32_t audio_bf_voc_get_saturation_limit(void)
+{
+    return audio_bf->saturation_limits;
+}
+
+static void print_fir(const char* member_name, volatile struct audio_bf_fir_coef_t* pfir)
+{
+    int i;
+    printf("  for(int i = 0; i < 9; i++){\n");
+    for (i = 0; i < 9; i++)
+    {
+        struct audio_bf_fir_coef_t fir = pfir[i];
+
+        printf("    audio_bf->%s[%d] = (struct audio_bf_fir_coef_t){\n", member_name, i);
+        printf("      .fir_tap0 = 0x%x,\n", fir.fir_tap0);
+        printf("      .fir_tap1 = 0x%x\n", fir.fir_tap1);
+        printf("    };\n");
+    }
+    printf("  }\n");
+}
+
+void audio_bf_print_setting(void)
+{
+    int i;
+    printf("void audio_bf_setting(void) {\n");
+    struct audio_bf_ch_cfg_t bf_ch_cfg_reg = audio_bf->bf_ch_cfg_reg;
+
+    printf("  audio_bf->bf_ch_cfg_reg = (struct audio_bf_ch_cfg_t){\n");
+    printf("    .we_audio_gain = 1, .we_bf_target_dir = 1, .we_bf_sound_ch_en = 1,\n");
+    printf("    .audio_gain = 0x%x, .bf_target_dir = %d, .bf_sound_ch_en = %d, .data_src_mode = %d\n",
+        bf_ch_cfg_reg.audio_gain, bf_ch_cfg_reg.bf_target_dir, bf_ch_cfg_reg.bf_sound_ch_en, bf_ch_cfg_reg.data_src_mode);
+    printf("  };\n");
+
+    struct audio_bf_ctl_t bf_ctl_reg = audio_bf->bf_ctl_reg;
+
+    printf("  audio_bf->bf_ctl_reg = (struct audio_bf_ctl_t){\n");
+    printf("    .we_bf_stream_gen = 1, .we_bf_dir_search_en = 1,\n");
+    printf("    .bf_stream_gen_en = %d, .bf_dir_search_en = %d\n",
+        bf_ctl_reg.bf_stream_gen_en, bf_ctl_reg.bf_dir_search_en);
+    printf("  };\n");
+
+    printf("  for(int i = 0; i < 16; i++){\n");
+    for (i = 0; i < 16; i++)
+    {
+        struct audio_bf_dir_bidx_t bidx0 = audio_bf->bf_dir_bidx[i][0];
+        struct audio_bf_dir_bidx_t bidx1 = audio_bf->bf_dir_bidx[i][1];
+
+        printf("    audio_bf->bf_dir_bidx[%d][0] = (struct audio_bf_dir_bidx_t){\n", i);
+        printf("      .dir_rd_idx0 = 0x%x,\n", bidx0.dir_rd_idx0);
+        printf("      .dir_rd_idx1 = 0x%x,\n", bidx0.dir_rd_idx1);
+        printf("      .dir_rd_idx2 = 0x%x,\n", bidx0.dir_rd_idx2);
+        printf("      .dir_rd_idx3 = 0x%x\n", bidx0.dir_rd_idx3);
+        printf("    };\n");
+        printf("    audio_bf->bf_dir_bidx[%d][1] = (struct audio_bf_dir_bidx_t){\n", i);
+        printf("      .dir_rd_idx0 = 0x%x,\n", bidx1.dir_rd_idx0);
+        printf("      .dir_rd_idx1 = 0x%x,\n", bidx1.dir_rd_idx1);
+        printf("      .dir_rd_idx2 = 0x%x,\n", bidx1.dir_rd_idx2);
+        printf("      .dir_rd_idx3 = 0x%x\n", bidx1.dir_rd_idx3);
+        printf("    };\n");
+    }
+    printf("  }\n");
+
+    print_fir("bf_pre_fir0_coef", audio_bf->bf_pre_fir0_coef);
+    print_fir("bf_post_fir0_coef", audio_bf->bf_post_fir0_coef);
+    print_fir("bf_pre_fir1_coef", audio_bf->bf_pre_fir1_coef);
+    print_fir("bf_post_fir1_coef", audio_bf->bf_post_fir1_coef);
+
+    struct audio_bf_dwsz_cfg_t bf_dwsz_cfg_reg = audio_bf->bf_dwsz_cfg_reg;
+
+    printf("  audio_bf->bf_dwsz_cfg_reg = (struct audio_bf_dwsz_cfg_t){\n");
+    printf("    .dir_dwn_siz_rate = %d, .voc_dwn_siz_rate = %d\n",
+        bf_dwsz_cfg_reg.dir_dwn_siz_rate, bf_dwsz_cfg_reg.voc_dwn_siz_rate);
+    printf("  };\n");
+
+    struct audio_bf_fft_cfg_t bf_fft_cfg_reg = audio_bf->bf_fft_cfg_reg;
+
+    printf("  audio_bf->bf_fft_cfg_reg = (struct audio_bf_fft_cfg_t){\n");
+    printf("    .fft_enable = %d, .fft_shift_factor = 0x%x\n",
+        bf_fft_cfg_reg.fft_enable, bf_fft_cfg_reg.fft_shift_factor);
+    printf("  };\n");
+
+    struct audio_bf_int_mask_t bf_int_mask_reg = audio_bf->bf_int_mask_reg;
+
+    printf("  audio_bf->bf_int_mask_reg = (struct audio_bf_int_mask_t){\n");
+    printf("    .dir_data_rdy_msk = %d, .voc_buf_rdy_msk = %d\n",
+        bf_int_mask_reg.dir_data_rdy_msk, bf_int_mask_reg.voc_buf_rdy_msk);
+    printf("  };\n");
+
+    printf("}\n");
+}

+ 276 - 0
lib/drivers/clint.c

@@ -0,0 +1,276 @@
+/* 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.
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include "env/encoding.h"
+#include "clint.h"
+#include "sysctl.h"
+
+struct clint_timer_instance_t
+{
+    uint64_t interval;
+    uint64_t cycles;
+    uint64_t single_shot;
+    clint_timer_callback_t callback;
+    void* ctx;
+};
+
+struct clint_ipi_instance_t
+{
+    clint_ipi_callback_t callback;
+    void* ctx;
+};
+
+volatile struct clint_t* const clint = (volatile struct clint_t*)CLINT_BASE_ADDR;
+static struct clint_timer_instance_t clint_timer_instance[CLINT_NUM_HARTS];
+static struct clint_ipi_instance_t clint_ipi_instance[CLINT_NUM_HARTS];
+
+uint64_t clint_get_time(void)
+{
+    /* No difference on harts */
+    return clint->mtime;
+}
+
+int clint_timer_init(void)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* Clear the Machine-Timer bit in MIE */
+    clear_csr(mie, MIP_MTIP);
+    /* Fill hart's instance with original data */
+
+    /* clang-format off */
+    clint_timer_instance[hart_id] = (const struct 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 sysctl_get_freq() / CLINT_CLOCK_DIV;
+}
+
+int clint_timer_start(uint64_t interval, int single_shot)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* 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[hart_id].interval == 0)
+        return -1;
+    /* Check settings to prevent cycles is 0 */
+    if (clint_timer_instance[hart_id].cycles == 0)
+        return -1;
+    /* Add cycle interval to mtimecmp */
+    uint64_t now = clint->mtime;
+    uint64_t then = now + clint_timer_instance[hart_id].cycles;
+    /* Set mtimecmp by hart id */
+    clint->mtimecmp[hart_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 hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    return clint_timer_instance[hart_id].interval;
+}
+
+int clint_timer_set_interval(uint64_t interval)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* Check parameter */
+    if (interval == 0)
+        return -1;
+
+    /* Assign user interval with Millisecond(ms) */
+    clint_timer_instance[hart_id].interval = interval;
+    /* Convert interval to cycles */
+    clint_timer_instance[hart_id].cycles = interval * clint_timer_get_freq() / 1000ULL;
+    return 0;
+}
+
+int clint_timer_get_single_shot(void)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* Get single shot mode by hart id */
+    return clint_timer_instance[hart_id].single_shot;
+}
+
+int clint_timer_set_single_shot(int single_shot)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* Set single shot mode by hart id */
+    clint_timer_instance[hart_id].single_shot = single_shot;
+    return 0;
+}
+
+int clint_timer_register(clint_timer_callback_t callback, void* ctx)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* Set user callback function */
+    clint_timer_instance[hart_id].callback = callback;
+    /* Assign user context */
+    clint_timer_instance[hart_id].ctx = ctx;
+    return 0;
+}
+
+int clint_timer_deregister(void)
+{
+    /* Just assign NULL to user callback function and context */
+    return clint_timer_register(NULL, NULL);
+}
+
+int clint_ipi_init(void)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* Clear the Machine-Software bit in MIE */
+    clear_csr(mie, MIP_MSIP);
+    /* Fill hart's instance with original data */
+    /* clang-format off */
+    clint_ipi_instance[hart_id] = (const struct 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 hart_id)
+{
+    if (hart_id >= CLINT_NUM_HARTS)
+        return -1;
+    clint->msip[hart_id].msip = 1;
+    return 0;
+}
+
+int clint_ipi_clear(size_t hart_id)
+{
+    if (hart_id >= CLINT_NUM_HARTS)
+        return -1;
+    if (clint->msip[hart_id].msip)
+    {
+        clint->msip[hart_id].msip = 0;
+        return 1;
+    }
+    return 0;
+}
+
+int clint_ipi_register(clint_ipi_callback_t callback, void* ctx)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* Set user callback function */
+    clint_ipi_instance[hart_id].callback = callback;
+    /* Assign user context */
+    clint_ipi_instance[hart_id].ctx = ctx;
+    return 0;
+}
+
+int clint_ipi_deregister(void)
+{
+    /* Just assign NULL to user callback function and context */
+    return clint_ipi_register(NULL, NULL);
+}
+
+uintptr_t handle_irq_m_timer(uintptr_t cause, uintptr_t epc, uintptr_t regs[32])
+{
+    /* Read hart id */
+    uint64_t hart_id = read_csr(mhartid);
+    uint64_t ie_flag = read_csr(mie);
+
+    clear_csr(mie, MIP_MTIP | MIP_MSIP);
+    set_csr(mstatus, MSTATUS_MIE);
+    if (clint_timer_instance[hart_id].callback != NULL)
+        clint_timer_instance[hart_id].callback(
+            clint_timer_instance[hart_id].ctx);
+    clear_csr(mstatus, MSTATUS_MIE);
+    set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
+    write_csr(mie, ie_flag);
+    /* If not single shot and cycle interval is not 0, repeat this timer */
+    if (!clint_timer_instance[hart_id].single_shot && clint_timer_instance[hart_id].cycles != 0)
+    {
+        /* Set mtimecmp by hart id */
+        clint->mtimecmp[hart_id] += clint_timer_instance[hart_id].cycles;
+    }
+    else
+        clear_csr(mie, MIP_MTIP);
+    return epc;
+}
+
+uintptr_t handle_irq_m_soft(uintptr_t cause, uintptr_t epc, uintptr_t regs[32])
+{
+    /* Read hart id */
+    uint64_t hart_id = read_csr(mhartid);
+    /* Clear the Machine-Software bit in MIE to prevent call again */
+    clear_csr(mie, MIP_MSIP);
+    set_csr(mstatus, MSTATUS_MIE);
+    /* Clear ipi flag */
+    clint_ipi_clear(hart_id);
+    if (clint_ipi_instance[hart_id].callback != NULL)
+        clint_ipi_instance[hart_id].callback(clint_ipi_instance[hart_id].ctx);
+    clear_csr(mstatus, MSTATUS_MIE);
+    set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
+    set_csr(mie, MIP_MSIP);
+    return epc;
+}
+

+ 55 - 0
lib/drivers/common.c

@@ -0,0 +1,55 @@
+/* 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.
+ */
+#include <stddef.h>
+#include "env/encoding.h"
+#include "common.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);
+}
+
+void machine_irq_enable(void)
+{
+    set_csr(mie, MIP_MEIP);
+    set_csr(mstatus, MSTATUS_MIE);
+}
+
+void machine_irq_disable(void)
+{
+    clear_csr(mie, MIP_MEIP);
+    clear_csr(mstatus, MSTATUS_MIE);
+}

+ 716 - 0
lib/drivers/dmac.c

@@ -0,0 +1,716 @@
+/* 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.
+ */
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include "dmac.h"
+#include "sysctl.h"
+#include "fpioa.h"
+#include "common.h"
+#include "plic.h"
+#include "stdlib.h"
+
+volatile struct dmac_t *const dmac = (struct dmac_t *)DMAC_BASE_ADDR;
+
+static int is_memory(uintptr_t address)
+{
+    enum { mem_len = 6 * 1024 * 1024 };
+    return ((address >= 0x80000000) && (address < 0x80000000 + mem_len)) || ((address >= 0x40000000) && (address < 0x40000000 + mem_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 channel_num)
+{
+    return dmac->channel[channel_num].axi_id;
+}
+
+void dmac_enable(void)
+{
+    union dmac_cfg_u  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)
+{
+    union dmac_cfg_u  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 channel_num)
+{
+    union dmac_ch_intstatus_enable_u  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 channel_num)
+{
+    union dmac_chen_u 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 channel_num)
+{
+    union dmac_chen_u chen;
+
+    chen.data = readq(&dmac->chen);
+
+    switch (channel_num) {
+    case DMAC_CHANNEL0:
+        chen.dmac_chen.ch1_en = 0;
+        chen.dmac_chen.ch1_en_we = 0;
+        break;
+    case DMAC_CHANNEL1:
+        chen.dmac_chen.ch2_en = 0;
+        chen.dmac_chen.ch2_en_we = 0;
+        break;
+    case DMAC_CHANNEL2:
+        chen.dmac_chen.ch3_en = 0;
+        chen.dmac_chen.ch3_en_we = 0;
+        break;
+    case DMAC_CHANNEL3:
+        chen.dmac_chen.ch4_en = 0;
+        chen.dmac_chen.ch4_en_we = 0;
+        break;
+    case DMAC_CHANNEL4:
+        chen.dmac_chen.ch5_en = 0;
+        chen.dmac_chen.ch5_en_we = 0;
+        break;
+    case DMAC_CHANNEL5:
+        chen.dmac_chen.ch6_en = 0;
+        chen.dmac_chen.ch6_en_we = 0;
+        break;
+    default:
+        break;
+    }
+
+    writeq(chen.data, &dmac->chen);
+}
+
+int32_t dmac_check_channel_busy(dmac_channel_number channel_num)
+{
+    int32_t ret = 0;
+    union dmac_chen_u 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 channel_num,
+    dmac_src_dst_select sd_sel, enum dmac_master_number  mst_num)
+{
+    int32_t ret = 0;
+    uint64_t tmp = 0;
+    union dmac_ch_ctl_u 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)
+{
+    union dmac_commonreg_intstatus_enable_u 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)
+{
+    union dmac_commonreg_intsignal_enable_u 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);
+}
+
+void dmac_enable_channel_interrupt_status(dmac_channel_number channel_num)
+{
+    writeq(0xffffffff, &dmac->channel[channel_num].intclear);
+    writeq(0xffffffff, &dmac->channel[channel_num].intstatus_en);
+}
+
+void dmac_disable_channel_interrupt_status(dmac_channel_number channel_num)
+{
+    writeq(0, &dmac->channel[channel_num].intstatus_en);
+}
+
+void dmac_enable_channel_interrupt_signal(dmac_channel_number channel_num,
+    enum dmca_common_int which_interrupt)
+{
+
+}
+
+void dmac_chanel_interrupt_clear(dmac_channel_number channel_num)
+{
+    writeq(0xffffffff, &dmac->channel[channel_num].intclear);
+}
+
+int dmac_set_channel_config(dmac_channel_number channel_num,
+        struct dmac_channel_config_t *cfg_param)
+{
+    union dmac_ch_ctl_u  ctl;
+    union dmac_ch_cfg_u cfg;
+    union dmac_ch_llp_u 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 channel_num,
+    void *src, void *dest, enum dmac_address_increment src_inc, enum dmac_address_increment dest_inc,
+    enum dmac_burst_trans_length dmac_msize,
+    enum dmac_transfer_width dmac_trans_width,
+    uint32_t blockSize)
+{
+    union dmac_ch_ctl_u  ctl;
+    union dmac_ch_cfg_u cfg_u;
+
+    int mem_type_src = is_memory((uintptr_t)src), mem_type_dest = is_memory((uintptr_t)dest);
+    enum dmac_transfer_flow 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 if (mem_type_src == 1 && mem_type_dest == 1)
+        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_msize;
+    ctl.ch_ctl.dst_msize = dmac_msize;
+
+    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 channel_num,
+        struct dmac_channel_config_t *cfg_param)
+{
+    union dmac_ch_ctl_u  ctl;
+    union dmac_ch_cfg_u cfg;
+    union dmac_ch_llp_u 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 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 channel_num,
+        uint32_t block_size)
+{
+    uint32_t block_ts;
+
+    block_ts = block_size & 0x3fffff;
+    writeq(block_ts, &dmac->channel[channel_num].block_ts);
+}
+
+void dmac_source_control(dmac_channel_number channel_num,
+        enum dmac_master_number master_select,
+        enum dmac_address_increment address_mode,
+        enum dmac_transfer_width tr_width,
+        enum dmac_burst_trans_length burst_length)
+{
+    union dmac_ch_ctl_u 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 channel_num,
+        enum dmac_master_number master_select,
+        enum dmac_address_increment address_mode,
+        enum dmac_transfer_width tr_width,
+        enum dmac_burst_trans_length burst_length)
+{
+    union dmac_ch_ctl_u 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 channel_num,
+                enum dmac_multiblk_transfer_type transfer_type,
+                enum dmac_sw_hw_hs_select handshak_select)
+{
+    union dmac_ch_cfg_u 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 channel_num,
+                enum dmac_multiblk_transfer_type transfer_type,
+                enum dmac_sw_hw_hs_select handshak_select)
+{
+    union dmac_ch_cfg_u 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 channel_num,
+            enum dmac_transfer_flow flow_control)
+{
+    union dmac_ch_cfg_u 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 channel_num,
+            uint64_t *addr)
+{
+    union dmac_ch_llp_u 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 dmac_init(void)
+{
+    uint64_t tmp;
+    union dmac_commonreg_intclear_u intclear;
+    union dmac_cfg_u dmac_cfg;
+    union dmac_reset_u 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 */
+}
+
+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 channel_num,
+    uint8_t LLI_row_num, int8_t LLI_last_row,
+    struct dmac_lli_item_t *lli_item,
+    struct dmac_channel_config_t *cfg_param)
+{
+    union dmac_ch_ctl_u ctl;
+    union dmac_ch_llp_u  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 channel_num,
+        int8_t last_block, struct dmac_channel_config_t *cfg_param)
+{
+    union dmac_ch_ctl_u 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 channel_num)
+{
+    union dmac_ch_ctl_u 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 channel_num,
+    void *src, void *dest, enum dmac_address_increment src_inc, enum dmac_address_increment dest_inc,
+    enum dmac_burst_trans_length dmac_msize,
+    enum dmac_transfer_width dmac_trans_width,
+    uint32_t blockSize)
+{
+    dmac_channel_disable(channel_num);
+    dmac_set_channel_param(channel_num, src, dest, src_inc,dest_inc,
+        dmac_msize,dmac_trans_width,blockSize);
+    dmac_enable();
+    dmac_chanel_interrupt_clear(channel_num); /* clear interrupt */
+    dmac_enable_channel_interrupt_status(channel_num);
+    dmac_channel_enable(channel_num);
+}
+
+void dmac_wait_done(dmac_channel_number channel_num)
+{
+    while (!(readq(&dmac->channel[channel_num].intstatus) & 0x2))
+        ;
+    dmac_chanel_interrupt_clear(channel_num); /* clear interrupt */
+}

+ 293 - 0
lib/drivers/dvp.c

@@ -0,0 +1,293 @@
+/* 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.
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include "dvp.h"
+#include "common.h"
+#include "fpioa.h"
+#include "sysctl.h"
+
+volatile struct dvp_t* const dvp = (volatile struct dvp_t*)DVP_BASE_ADDR;
+static uint8_t reg_len = 8;
+
+void mdelay(uint32_t ms)
+{
+    uint32_t i;
+
+    while (ms && ms--)
+    {
+        for (i = 0; i < 25000; i++)
+            __asm__ __volatile__("nop");
+    }
+}
+
+static void dvp_sccb_clk_init(void)
+{
+    uint32_t tmp;
+
+    tmp = dvp->sccb_cfg & (~(DVP_SCCB_SCL_LCNT_MASK | DVP_SCCB_SCL_HCNT_MASK));
+    tmp |= DVP_SCCB_SCL_LCNT(500) | DVP_SCCB_SCL_HCNT(500);
+
+    dvp->sccb_cfg = tmp;
+}
+
+static void dvp_sccb_start_transfer(void)
+{
+    while (dvp->sts & DVP_STS_SCCB_EN)
+        ;
+    dvp->sts = DVP_STS_SCCB_EN | DVP_STS_SCCB_EN_WE;
+    while (dvp->sts & DVP_STS_SCCB_EN)
+        ;
+}
+
+int dvp_sccb_write(uint8_t dev_addr, uint16_t reg_addr, uint8_t reg_data)
+{
+    uint32_t tmp;
+
+    tmp = dvp->sccb_cfg & (~DVP_SCCB_BYTE_NUM_MASK);
+
+    (reg_len == 8) ? (tmp |= DVP_SCCB_BYTE_NUM_3) : (tmp |= DVP_SCCB_BYTE_NUM_4);
+
+    dvp->sccb_cfg = tmp;
+
+    if (reg_len == 8)
+    {
+        dvp->sccb_ctl = DVP_SCCB_WRITE_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr) | DVP_SCCB_WDATA_BYTE0(reg_data);
+    }
+    else
+    {
+        dvp->sccb_ctl = DVP_SCCB_WRITE_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr >> 8) | DVP_SCCB_WDATA_BYTE0(reg_addr & 0xff) | DVP_SCCB_WDATA_BYTE1(reg_data);
+    }
+    dvp_sccb_start_transfer();
+
+    return 0;
+}
+
+uint8_t dvp_sccb_read(uint8_t dev_addr, uint16_t reg_addr)
+{
+    uint32_t tmp;
+
+    tmp = dvp->sccb_cfg & (~DVP_SCCB_BYTE_NUM_MASK);
+    (reg_len == 8) ? (tmp |= DVP_SCCB_BYTE_NUM_2) : (tmp |= DVP_SCCB_BYTE_NUM_3);
+
+    dvp->sccb_cfg = tmp;
+
+    if (reg_len == 8)
+    {
+        dvp->sccb_ctl = DVP_SCCB_WRITE_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr);
+    }
+    else
+    {
+        dvp->sccb_ctl = DVP_SCCB_WRITE_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr >> 8) | DVP_SCCB_WDATA_BYTE0(reg_addr & 0xff);
+    }
+    dvp_sccb_start_transfer();
+
+    dvp->sccb_ctl = DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr);
+
+    dvp_sccb_start_transfer();
+
+    return DVP_SCCB_RDATA_BYTE(dvp->sccb_cfg);
+}
+
+static void dvp_io_init(void)
+{
+    /* Init DVP IO map and function settings */
+    fpioa_set_function(15, FUNC_CMOS_RST);
+    fpioa_set_function(17, FUNC_CMOS_PWND);
+    fpioa_set_function(20, FUNC_CMOS_XCLK);
+    fpioa_set_function(18, FUNC_CMOS_VSYNC);
+    fpioa_set_function(19, FUNC_CMOS_HREF);
+    fpioa_set_function(21, FUNC_CMOS_PCLK);
+    fpioa_set_function(22, FUNC_SCCB_SCLK);
+    fpioa_set_function(23, FUNC_SCCB_SDA);
+    sysctl->misc.reserved0 = 1;
+}
+
+static void dvp_reset(void)
+{
+    /* First power down */
+    dvp->cmos_cfg |= DVP_CMOS_POWER_DOWN;
+    mdelay(200);
+    dvp->cmos_cfg &= ~DVP_CMOS_POWER_DOWN;
+    mdelay(200);
+
+    /* Second reset */
+    dvp->cmos_cfg &= ~DVP_CMOS_RESET;
+    mdelay(200);
+    dvp->cmos_cfg |= DVP_CMOS_RESET;
+    mdelay(200);
+}
+
+int dvp_init(uint8_t reglen)
+{
+    reg_len = reglen;
+    sysctl_clock_enable(SYSCTL_CLOCK_DVP);
+    sysctl_reset(SYSCTL_RESET_DVP);
+    dvp->cmos_cfg &= (~DVP_CMOS_CLK_DIV_MASK);
+    dvp->cmos_cfg |= DVP_CMOS_CLK_DIV(0) | DVP_CMOS_CLK_ENABLE;
+    dvp_io_init();
+    dvp_sccb_clk_init();
+    dvp_reset();
+
+    return 0;
+}
+
+int dvp_set_image_format(uint32_t format)
+{
+    uint32_t tmp;
+
+    tmp = dvp->dvp_cfg & (~DVP_CFG_FORMAT_MASK);
+    dvp->dvp_cfg = tmp | format;
+
+    return 0;
+}
+
+void dvp_burst_enable(void)
+{
+    dvp->dvp_cfg |= DVP_CFG_BURST_SIZE_4BEATS;
+
+    dvp->axi &= (~DVP_AXI_GM_MLEN_MASK);
+    dvp->axi |= DVP_AXI_GM_MLEN_4BYTE;
+}
+
+void dvp_burst_disable(void)
+{
+    dvp->dvp_cfg &= (~DVP_CFG_BURST_SIZE_4BEATS);
+
+    dvp->axi &= (~DVP_AXI_GM_MLEN_MASK);
+    dvp->axi |= DVP_AXI_GM_MLEN_1BYTE;
+}
+
+int dvp_set_image_size(uint32_t width, uint32_t height)
+{
+    uint32_t tmp;
+
+    tmp = dvp->dvp_cfg & (~(DVP_CFG_HREF_BURST_NUM_MASK | DVP_CFG_LINE_NUM_MASK));
+
+    tmp |= DVP_CFG_LINE_NUM(height);
+
+    if (dvp->dvp_cfg & DVP_CFG_BURST_SIZE_4BEATS)
+        tmp |= DVP_CFG_HREF_BURST_NUM(width / 8 / 4);
+    else
+        tmp |= DVP_CFG_HREF_BURST_NUM(width / 8 / 1);
+
+    dvp->dvp_cfg = tmp;
+
+    return 0;
+}
+
+int dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr)
+{
+    dvp->r_addr = r_addr;
+    dvp->g_addr = g_addr;
+    dvp->b_addr = b_addr;
+
+    return 0;
+}
+
+int dvp_set_display_addr(uint32_t addr)
+{
+    dvp->rgb_addr = addr;
+
+    return 0;
+}
+
+int dvp_frame_start(void)
+{
+    while (!(dvp->sts & DVP_STS_FRAME_START))
+        ;
+    dvp->sts = (DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE);
+
+    return 0;
+}
+
+void dvp_convert_start(void)
+{
+    dvp->sts = DVP_STS_DVP_EN | DVP_STS_DVP_EN_WE;
+}
+
+int dvp_convert_finish(void)
+{
+    while (!(dvp->sts & DVP_STS_FRAME_FINISH))
+        ;
+    dvp->sts = DVP_STS_FRAME_FINISH | DVP_STS_FRAME_FINISH_WE;
+
+    return 0;
+}
+
+int dvp_get_image(void)
+{
+    while (!(dvp->sts & DVP_STS_FRAME_START))
+        ;
+    dvp->sts = DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE;
+    while (!(dvp->sts & DVP_STS_FRAME_START))
+        ;
+    dvp->sts = DVP_STS_FRAME_FINISH | DVP_STS_FRAME_FINISH_WE | DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE | DVP_STS_DVP_EN | DVP_STS_DVP_EN_WE;
+    while (!(dvp->sts & DVP_STS_FRAME_FINISH))
+        ;
+
+    return 0;
+}
+
+void dvp_interrupt_config(uint32_t interrupt, uint8_t status)
+{
+    if (status)
+        dvp->dvp_cfg |= interrupt;
+    else
+        dvp->dvp_cfg &= (~interrupt);
+}
+
+int dvp_interrupt_get(uint32_t interrupt)
+{
+    if (dvp->sts & interrupt)
+        return 1;
+    return 0;
+}
+
+void dvp_interrupt_clear(uint32_t interrupt)
+{
+    interrupt |= (interrupt << 1);
+    dvp->sts |= interrupt;
+}
+
+void dvp_enable_auto(void)
+{
+    dvp->dvp_cfg |= DVP_CFG_AUTO_ENABLE;
+}
+
+void dvp_disable_auto(void)
+{
+    dvp->dvp_cfg &= (~DVP_CFG_AUTO_ENABLE);
+}
+
+void dvp_set_output_enable(size_t index, int enable)
+{
+    configASSERT(index < 2);
+
+    if (index == 0)
+    {
+        if (enable)
+            dvp->dvp_cfg |= DVP_CFG_AI_OUTPUT_ENABLE;
+        else
+            dvp->dvp_cfg &= ~DVP_CFG_AI_OUTPUT_ENABLE;
+    }
+    else
+    {
+        if (enable)
+            dvp->dvp_cfg |= DVP_CFG_DISPLAY_OUTPUT_ENABLE;
+        else
+            dvp->dvp_cfg &= ~DVP_CFG_DISPLAY_OUTPUT_ENABLE;
+    }
+}

+ 5398 - 0
lib/drivers/fpioa.c

@@ -0,0 +1,5398 @@
+/* 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.
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include "sysctl.h"
+#include "fpioa.h"
+
+volatile struct fpioa_t *const fpioa = (volatile struct fpioa_t *)FPIOA_BASE_ADDR;
+
+/**
+ * @brief      Internal used FPIOA function initialize cell
+ *
+ *             This is NOT fpioa_io_config_t, can't assign directly
+ *
+ */
+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)));
+
+/* Function list */
+static const struct 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_CLK_IN1,
+        .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_IN2,
+        .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_PWND,
+        .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  = 217,
+        .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  = 218,
+        .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_INTERNAL13,
+        .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_INTERNAL14,
+        .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_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_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_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_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 fpioa_init(void)
+{
+    int i = 0;
+
+    /* Enable fpioa clock in system controller */
+    sysctl_clock_enable(SYSCTL_CLOCK_FPIOA);
+
+    /* Initialize tie */
+    struct 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, struct 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, struct 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, enum fpioa_pull_e pull)
+{
+    /* Check parameters */
+    if (number < 0 || number >= FPIOA_NUM_IO || pull >= FPIOA_PULL_MAX)
+        return -1;
+
+    /* Atomic read register */
+    struct 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;
+
+    enum fpioa_pull_e pull;
+    /* Atomic read register */
+    struct 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, enum fpioa_driving_e driving)
+{
+    /* Check parameters */
+    if (number < 0 || number >= FPIOA_NUM_IO || driving >= FPIOA_DRIVING_MAX)
+        return -1;
+
+    /* Atomic read register */
+    struct 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_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, enum fpioa_function_e function)
+{
+    /* Check parameters */
+    if (number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX)
+        return -1;
+    /* Atomic write register */
+    fpioa->io[number] =(const struct 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 fpioa_set_function(int number, enum fpioa_function_e 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(enum fpioa_function_e 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(enum fpioa_function_e 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_func(enum fpioa_function_e function)
+{
+    int index = 0;
+    for (index = 0; index < FPIOA_NUM_IO; index++)
+    {
+        if (fpioa->io[index].ch_sel == function)
+            return index;
+    }
+
+    return -1;
+}

+ 86 - 0
lib/drivers/gpio.c

@@ -0,0 +1,86 @@
+/* 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.
+ */
+#include "gpio.h"
+#include "common.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)
+{
+    sysctl_clock_enable(SYSCTL_CLOCK_GPIO);
+    return 0;
+}
+
+void gpio_pin_init(size_t pin_num, size_t gpio_pin)
+{
+    configASSERT(gpio_pin < GPIO_MAX_PINNO);
+    fpioa_set_function(pin_num, FUNC_GPIO0 + gpio_pin);
+}
+
+void gpio_set_drive_mode(size_t pin, gpio_drive_mode mode)
+{
+    configASSERT(pin < GPIO_MAX_PINNO);
+    int io_number = fpioa_get_io_by_func(FUNC_GPIO0 + pin);
+    configASSERT(io_number > 0);
+
+    enum fpioa_pull_e pull;
+    uint32_t dir;
+
+    switch (mode)
+    {
+    case GPIO_DM_Input:
+        pull = FPIOA_PULL_NONE;
+        dir = 0;
+        break;
+    case GPIO_DM_InputPullDown:
+        pull = FPIOA_PULL_DOWN;
+        dir = 0;
+        break;
+    case GPIO_DM_InputPullUp:
+        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 gpio_get_pin_value(size_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_value(size_t pin, gpio_pin_value 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);
+}
+

+ 184 - 0
lib/drivers/gpiohs.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.
+ */
+#include "gpiohs.h"
+#include "common.h"
+#include "fpioa.h"
+#include "sysctl.h"
+#define GPIOHS_MAX_PINNO 32
+
+volatile gpiohs_t* const gpiohs = (volatile gpiohs_t*)GPIOHS_BASE_ADDR;
+
+struct gpiohs_pin_context
+{
+    size_t pin;
+    gpio_pin_edge edge;
+    void (*callback)();
+} pin_context[32];
+
+int gpiohs_init(void)
+{
+    gpiohs->rise_ie.u32[0] = 0;
+    gpiohs->rise_ip.u32[0] = 0xFFFFFFFF;
+    gpiohs->fall_ie.u32[0] = 0;
+    gpiohs->fall_ip.u32[0] = 0xFFFFFFFF;
+    return 0;
+}
+
+void gpiohs_pin_init(size_t pin_num, size_t gpio_pin)
+{
+    configASSERT(gpio_pin < GPIOHS_MAX_PINNO);
+    fpioa_set_function(pin_num, FUNC_GPIOHS0 + gpio_pin);
+}
+
+void gpiohs_set_drive_mode(size_t pin, gpio_drive_mode mode)
+{
+    configASSERT(pin < GPIOHS_MAX_PINNO);
+    int io_number = fpioa_get_io_by_func(FUNC_GPIOHS0 + pin);
+    configASSERT(io_number > 0);
+
+    enum fpioa_pull_e pull;
+    uint32_t dir;
+
+    switch (mode)
+    {
+    case GPIO_DM_Input:
+        pull = FPIOA_PULL_NONE;
+        dir = 0;
+        break;
+    case GPIO_DM_InputPullDown:
+        pull = FPIOA_PULL_DOWN;
+        dir = 0;
+        break;
+    case GPIO_DM_InputPullUp:
+        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 gpiohs_get_pin_value(size_t pin)
+{
+    configASSERT(pin < GPIOHS_MAX_PINNO);
+    return get_gpio_bit(gpiohs->input_val.u32, pin);
+}
+
+void gpiohs_set_pin_value(size_t pin, gpio_pin_value value)
+{
+    configASSERT(pin < GPIOHS_MAX_PINNO);
+    set_gpio_bit(gpiohs->output_val.u32, pin, value);
+}
+
+void gpiohs_set_pin_edge(size_t pin, gpio_pin_edge edge)
+{
+    uint32_t rise, fall, irq;
+    switch (edge)
+    {
+    case GPIO_PE_None:
+        rise = fall = irq = 0;
+        break;
+    case GPIO_PE_Falling:
+        rise = 0;
+        fall = irq = 1;
+        break;
+    case GPIO_PE_Rising:
+        fall = 0;
+        rise = irq = 1;
+        break;
+    case GPIO_PE_Both:
+        rise = fall = irq = 1;
+        break;
+    default:
+        configASSERT(!"Invalid gpio edge");
+        break;
+    }
+
+    set_gpio_bit(gpiohs->rise_ie.u32, pin, rise);
+    set_gpio_bit(gpiohs->fall_ie.u32, pin, fall);
+    pin_context[pin].edge = edge;
+}
+
+int gpiohs_pin_onchange_isr(void* userdata)
+{
+    struct gpiohs_pin_context* ctx = (struct gpiohs_pin_context*)userdata;
+    size_t pin = ctx->pin;
+    uint32_t rise, fall;
+    switch (ctx->edge)
+    {
+    case GPIO_PE_None:
+        rise = fall = 0;
+        break;
+    case GPIO_PE_Falling:
+        rise = 0;
+        fall = 1;
+        break;
+    case GPIO_PE_Rising:
+        fall = 0;
+        rise = 1;
+        break;
+    case GPIO_PE_Both:
+        rise = fall = 1;
+        break;
+    default:
+        configASSERT(!"Invalid gpio edge");
+        break;
+    }
+
+    if (rise)
+    {
+        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 (fall)
+    {
+        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->callback)
+        ctx->callback();
+    return 0;
+}
+
+void gpiohs_set_irq(size_t pin, uint32_t priority, void (*func)())
+{
+
+    pin_context[pin].pin = pin;
+    pin_context[pin].callback = func;
+
+    plic_set_priority(IRQN_GPIOHS0_INTERRUPT + pin, priority);
+    plic_irq_register(IRQN_GPIOHS0_INTERRUPT + pin, gpiohs_pin_onchange_isr, &(pin_context[pin]));
+    plic_irq_enable(IRQN_GPIOHS0_INTERRUPT + pin);
+}
+
+void gpiohs_irq_disable(size_t pin)
+{
+    plic_irq_disable(IRQN_GPIOHS0_INTERRUPT + pin);
+}
+

+ 150 - 0
lib/drivers/hard_fft.c

@@ -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.
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include "env/encoding.h"
+#include "hard_fft.h"
+#include "platform.h"
+#include "syscalls.h"
+#include "sysctl.h"
+
+#define FFT_RESULT_ADDR (0x42100000 + 0x2000)
+volatile uint64_t* fft_result = (volatile uint64_t*)FFT_RESULT_ADDR;
+
+volatile fft_t* const fft = (volatile fft_t*)FFT_BASE_ADDR;
+
+int fft_init(uint8_t point, uint8_t mode, uint16_t shift, uint8_t is_dma, uint8_t input_mode, uint8_t data_mode)
+{
+    fft->fft_ctrl.fft_point = point; /* 0:512, 1:256, 2:128, 3:64 */
+    fft->fft_ctrl.fft_mode = mode;   /* 1: fft, 0: ifft */
+    fft->fft_ctrl.fft_shift = shift;
+    fft->fft_ctrl.dma_send = is_dma;
+    fft->fft_ctrl.fft_enable = 1;
+    fft->fft_ctrl.fft_input_mode = input_mode;
+    fft->fft_ctrl.fft_data_mode = data_mode;
+    return 0;
+}
+
+void fft_reset(void)
+{
+    fft->fifo_ctrl.resp_fifo_flush_n = 0;
+    fft->fifo_ctrl.cmd_fifo_flush_n = 0;
+    fft->fifo_ctrl.gs_fifo_flush_n = 0;
+}
+
+void fft_enable_int(void)
+{
+    fft->intr_mask.fft_done_mask = 1;
+}
+
+void fft_input_data(float* x, float* y, uint8_t point)
+{
+    uint16_t point_num = 0;
+    uint16_t i;
+    fft_data input_data;
+
+    if (point == 0)
+        point_num = 512;
+    else if (point == 1)
+        point_num = 256;
+    else if (point == 2)
+        point_num = 128;
+    else if (point == 3)
+        point_num = 64;
+    point_num = point_num / 2; /* one time send two data */
+
+    for (i = 0; i < point_num; i++)
+    {
+        input_data.R1 = (int16_t)(x[2 * i] * 32);
+        input_data.I1 = (int16_t)(y[2 * i] * 32);
+        input_data.R2 = (int16_t)(x[2 * i + 1] * 32);
+        input_data.I2 = (int16_t)(y[2 * i + 1] * 32);
+
+        fft->fft_input_fifo.fft_input_fifo = *(uint64_t*)&input_data;
+        printf("%d, %d\n", input_data.R1, input_data.I1);
+        printf("%d, %d\n", input_data.R2, input_data.I2);
+    }
+}
+
+void fft_input_intdata(int16_t* data, uint8_t point)
+{
+    uint16_t point_num = 0;
+    uint16_t i;
+    fft_data input_data;
+
+    if (point == 0)
+        point_num = 512;
+    else if (point == 1)
+        point_num = 256;
+    else if (point == 2)
+        point_num = 128;
+    else if (point == 3)
+        point_num = 64;
+    point_num = point_num / 2; /* one time send two data */
+
+    for (i = 0; i < point_num; i++)
+    {
+        input_data.R1 = data[2 * i];
+        input_data.I1 = 0;
+        input_data.R2 = data[2 * i + 1];
+        input_data.I2 = 0;
+
+        fft->fft_input_fifo.fft_input_fifo = *(uint64_t*)&input_data;
+    }
+}
+
+uint8_t fft_get_finish_flag(void)
+{
+    return (uint8_t)fft->fft_status.fft_done_status & 0x01;
+}
+
+void FixToDou(float* fData, uint32_t u32Data)
+{
+    if (u32Data & 0x8000)
+        *fData = -((float)(u32Data & 0x7fff)) / 32;
+    else
+        *fData = ((float)u32Data) / 32;
+}
+
+void fft_get_result(float* x, float* y, uint8_t point)
+{
+    uint64_t u64Data;
+    uint16_t point_num = 0;
+    uint16_t i;
+    fft_data output_data;
+
+    if (point == 0)
+        point_num = 512;
+    else if (point == 1)
+        point_num = 256;
+    else if (point == 2)
+        point_num = 128;
+    else if (point == 3)
+        point_num = 64;
+    point_num = point_num / 2;
+
+    for (i = 0; i < point_num; i++)
+    {
+        u64Data = fft_result[i]; /*fft->fft_output_fifo.fft_output_fifo;*/
+
+        output_data = *(fft_data*)&u64Data;
+
+        x[2 * i] = ((float)output_data.R1) / 32;
+        y[2 * i] = ((float)output_data.I1) / 32;
+        x[2 * i + 1] = ((float)output_data.R2) / 32;
+        y[2 * i + 1] = ((float)output_data.I2) / 32;
+    }
+}
+

+ 196 - 0
lib/drivers/i2c.c

@@ -0,0 +1,196 @@
+/* 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.
+ */
+#include <stddef.h>
+#include "i2c.h"
+#include "common.h"
+#include "fpioa.h"
+#include "platform.h"
+#include "stdlib.h"
+#include "string.h"
+#include "sysctl.h"
+
+volatile struct i2c_t* const i2c[3] =
+{
+    (volatile struct i2c_t*)I2C0_BASE_ADDR,
+    (volatile struct i2c_t*)I2C1_BASE_ADDR,
+    (volatile struct i2c_t*)I2C2_BASE_ADDR
+};
+
+void i2c_pin_init(uint8_t sel, int clk_pin, int data_pin)
+{
+    configASSERT(sel < I2C_MAX_NUM);
+    fpioa_set_function(clk_pin, FUNC_I2C0_SCLK + (2 * sel));
+    fpioa_set_function(data_pin, FUNC_I2C0_SDA + (2 * sel));
+}
+
+void i2c_clk_init(uint8_t sel)
+{
+    configASSERT(sel < I2C_MAX_NUM);
+    sysctl_clock_enable(SYSCTL_CLOCK_I2C0 + sel);
+    sysctl_clock_set_threshold(SYSCTL_THRESHOLD_I2C0 + sel, 3);
+}
+
+void i2c_init(uint8_t sel, int clk_pin, int data_pin)
+{
+    configASSERT(sel < I2C_MAX_NUM);
+    i2c_pin_init(sel, clk_pin, data_pin);
+    i2c_clk_init(sel);
+    dmac_init();
+}
+
+void i2c_config(uint8_t sel, size_t slaveAddress, size_t address_width,i2c_bus_speed_mode bus_speed_mode)
+{
+    configASSERT(sel < I2C_MAX_NUM);
+    configASSERT(address_width == 7 || address_width == 10);
+    int speed_mode = 1;
+    switch (bus_speed_mode)
+    {
+        case I2C_BS_STANDARD:
+            speed_mode = 1;
+            break;
+        default:
+            break;
+    }
+    /*set config*/
+    volatile struct i2c_t* i2c_adapter = i2c[sel];
+    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(speed_mode);
+    i2c_adapter->ss_scl_hcnt = I2C_SS_SCL_HCNT_COUNT(37);
+    i2c_adapter->ss_scl_lcnt = I2C_SS_SCL_LCNT_COUNT(40);
+    i2c_adapter->tar = I2C_TAR_ADDRESS(slaveAddress);
+    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;
+}
+
+int i2c_write_reg(uint8_t sel, uint8_t reg, uint8_t* data_buf, uint8_t length)
+{
+    configASSERT(sel < I2C_MAX_NUM);
+    volatile struct i2c_t* i2c_adapter = i2c[sel];
+    uint8_t fifo_len, index;
+
+    fifo_len = length < 7 ? length : 7;
+    i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(reg);
+    for (index = 0; index < fifo_len; index++)
+        i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(*data_buf++);
+    length -= fifo_len;
+    while (length)
+    {
+        fifo_len = 8 - i2c_adapter->txflr;
+        fifo_len = length < fifo_len ? length : fifo_len;
+        for (index = 0; index < fifo_len; index++)
+            i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(*data_buf++);
+        if (i2c_adapter->tx_abrt_source != 0)
+            return 1;
+        length -= fifo_len;
+    }
+    while (i2c_adapter->status & I2C_STATUS_ACTIVITY)
+        ;
+    return 0;
+}
+
+int i2c_write_reg_dma(dmac_channel_number channel_num, uint8_t sel, uint8_t reg, uint8_t* data_buf, uint8_t length)
+{
+    configASSERT(sel < I2C_MAX_NUM);
+    volatile struct i2c_t* i2c_adapter = i2c[sel];
+
+    uint32_t* buf = malloc((length + 1) * sizeof(uint32_t));
+    buf[0] = reg;
+    int i;
+    for (i = 0; i < length + 1; i++)
+    {
+        buf[i + 1] = data_buf[i];
+    }
+
+    sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2C0_TX_REQ + sel * 2);
+    dmac_set_single_mode(channel_num, buf, (void*)(&i2c_adapter->data_cmd), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
+        DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, length + 1);
+
+    dmac_wait_done(channel_num);
+    free((void*)buf);
+
+    while (i2c_adapter->status & I2C_STATUS_ACTIVITY)
+    {
+        if (i2c_adapter->tx_abrt_source != 0)
+            configASSERT(!"source abort");
+    }
+    return 0;
+}
+
+int i2c_read_reg(uint8_t sel, uint8_t reg, uint8_t* data_buf, uint8_t length)
+{
+    uint8_t fifo_len, index;
+    uint8_t rx_len = length;
+    configASSERT(sel < I2C_MAX_NUM);
+    volatile struct i2c_t* i2c_adapter = i2c[sel];
+
+    fifo_len = length < 7 ? length : 7;
+    i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(reg);
+    for (index = 0; index < fifo_len; index++)
+        i2c_adapter->data_cmd = I2C_DATA_CMD_CMD;
+    length -= fifo_len;
+    while (length || rx_len)
+    {
+        fifo_len = i2c_adapter->rxflr;
+        fifo_len = rx_len < fifo_len ? rx_len : fifo_len;
+        for (index = 0; index < fifo_len; index++)
+            *data_buf++ = i2c_adapter->data_cmd;
+        rx_len -= fifo_len;
+        fifo_len = 8 - i2c_adapter->txflr;
+        fifo_len = length < fifo_len ? length : 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;
+        length -= fifo_len;
+    }
+    return 0;
+}
+
+int i2c_read_reg_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num,
+    uint8_t sel, uint8_t reg, uint8_t* data_buf, uint8_t length)
+{
+    configASSERT(sel < I2C_MAX_NUM);
+    volatile struct i2c_t* i2c_adapter = i2c[sel];
+
+    uint32_t* write_cmd = malloc(sizeof(uint32_t) * (1 + length));
+    size_t i;
+    write_cmd[0] = reg;
+    for (i = 0; i < length; i++)
+        write_cmd[i + 1] = I2C_DATA_CMD_CMD;
+
+    sysctl_dma_select(w_channel_num, SYSCTL_DMA_SELECT_I2C0_TX_REQ + sel * 2);
+    sysctl_dma_select(r_channel_num, SYSCTL_DMA_SELECT_I2C0_RX_REQ + sel * 2);
+
+    dmac_set_single_mode(r_channel_num, (void*)(&i2c_adapter->data_cmd), write_cmd, DMAC_ADDR_NOCHANGE,
+         DMAC_ADDR_INCREMENT,DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
+
+    dmac_set_single_mode(w_channel_num, write_cmd, (void*)(&i2c_adapter->data_cmd), DMAC_ADDR_INCREMENT,
+         DMAC_ADDR_NOCHANGE,DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, length + 1);
+
+    dmac_wait_done(w_channel_num);
+    dmac_wait_done(r_channel_num);
+
+    for (i = 0; i < length; i++)
+    {
+        data_buf[i] = write_cmd[i];
+    }
+
+    free(write_cmd);
+    return 0;
+}

+ 702 - 0
lib/drivers/i2s.c

@@ -0,0 +1,702 @@
+/* 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.
+ */
+#include <stdint.h>
+#include <stdio.h>
+#include "i2s.h"
+#include "sysctl.h"
+#include "stdlib.h"
+
+volatile struct i2s_t *const i2s[3] =
+{
+    (volatile struct i2s_t *)I2S0_BASE_ADDR,
+    (volatile struct i2s_t *)I2S1_BASE_ADDR,
+    (volatile struct i2s_t *)I2S2_BASE_ADDR
+};
+
+void i2s_init(enum i2s_device_num_t device_num, enum i2s_transmit_t rxtx_mode, uint32_t channel_mask)
+{
+    sysctl_clock_enable(SYSCTL_CLOCK_I2S0 + device_num);
+    sysctl_reset(SYSCTL_RESET_I2S0  + device_num);
+    sysctl_clock_set_threshold(SYSCTL_THRESHOLD_I2S0  + device_num, 7);
+    /*96k:5,44k:12,24k:23,22k:25 16k:35 sampling*/
+    /*sample rate*32bit*2 =75MHz/((N+1)*2) */
+    i2s_device_enable(device_num);
+    i2s_disable_block(device_num, TRANSMITTER);
+    i2s_disable_block(device_num, RECEIVER);
+
+    if (rxtx_mode == TRANSMITTER)
+    {
+        for (int i=0; i<4; i++)
+        {
+            if ((channel_mask & 0x3) == 0x3)
+            {
+                i2s_set_mask_interrupt(device_num, CHANNEL_0 + i, 1, 1, 1, 1);
+                i2s_transimit_enable(device_num, CHANNEL_0 + i);
+            }
+            else
+            {
+                i2s_transmit_channel_enable(device_num, CHANNEL_0 + i, 0);
+            }
+            channel_mask >>= 2;
+        }
+        i2s_transmit_dma_enable(device_num, 1);
+    }
+    else
+    {
+        for (int i=0; i<4; i++)
+        {
+            if ((channel_mask & 0x3) == 0x3)
+            {
+                i2s_set_mask_interrupt(device_num, CHANNEL_0 + i, 1, 1, 1, 1);
+                i2s_receive_enable(device_num, CHANNEL_0 + i);
+            }
+            else
+            {
+                i2s_receive_channel_enable(device_num, CHANNEL_0 + i, 0);
+            }
+            channel_mask >>= 2;
+        }
+        i2s_receive_dma_enable(device_num, 1);
+    }
+}
+
+void i2s_device_enable(enum i2s_device_num_t device_num)
+{
+    union ier_u u_ier;
+
+    u_ier.reg_data = readl(&i2s[device_num]->ier);
+    u_ier.ier.ien = 1;
+    writel(u_ier.reg_data, &i2s[device_num]->ier);
+}
+
+void i2s_dev_enable(enum i2s_device_num_t device_num, uint32_t enable)
+{
+    union ier_u u_ier;
+
+    u_ier.reg_data = readl(&i2s[device_num]->ier);
+    u_ier.ier.ien = enable;
+    writel(u_ier.reg_data, &i2s[device_num]->ier);
+}
+
+void i2s_disable_block(enum i2s_device_num_t device_num, enum i2s_transmit_t rxtx_mode)
+{
+    union irer_u u_irer;
+    union iter_u u_iter;
+
+    if (rxtx_mode == RECEIVER)
+    {
+        u_irer.reg_data = readl(&i2s[device_num]->irer);
+        u_irer.irer.rxen = 0;
+        writel(u_irer.reg_data, &i2s[device_num]->irer);
+        /* Receiver block disable */
+    }
+    else
+    {
+        u_iter.reg_data = readl(&i2s[device_num]->iter);
+        u_iter.iter.txen = 0;
+        writel(u_iter.reg_data, &i2s[device_num]->iter);
+        /* Transmitter block disable */
+    }
+}
+
+void i2s_receive_enable(enum i2s_device_num_t device_num, enum i2s_channel_num_t channel_num)
+{
+    union irer_u u_irer;
+
+    u_irer.reg_data = readl(&i2s[device_num]->irer);
+    u_irer.irer.rxen = 1;
+    writel(u_irer.reg_data, &i2s[device_num]->irer);
+    /* Receiver block enable */
+
+    i2s_receive_channel_enable(device_num, channel_num, 1);
+    /* Receive channel enable */
+}
+
+void i2s_transimit_enable(enum i2s_device_num_t device_num, enum i2s_channel_num_t channel_num)
+{
+    union iter_u u_iter;
+
+    u_iter.reg_data = readl(&i2s[device_num]->iter);
+    u_iter.iter.txen = 1;
+    writel(u_iter.reg_data, &i2s[device_num]->iter);
+    /* Transmitter block enable */
+
+    i2s_transmit_channel_enable(device_num, channel_num, 1);
+    /* Transmit channel enable */
+}
+
+void i2s_rx_channel_configure(enum i2s_device_num_t device_num,
+    enum i2s_channel_num_t channel_num,
+    enum word_length_t word_length,
+    enum word_select_cycles_t word_select_size,
+    enum fifo_threshold_t trigger_level,
+    enum i2s_work_mode_t word_mode)
+{
+    i2s_receive_channel_enable(device_num, channel_num, 0);
+    /* Receive channel disable */
+
+    writel(0, &i2s[device_num]->channel[channel_num].ter);
+    /* disable tx */
+
+    writel(1, &i2s[device_num]->channel[channel_num].rff);
+    /* flash individual fifo */
+
+    writel(1, &i2s[device_num]->rxffr);
+    /* flush tx fifo*/
+
+    i2s_set_rx_word_length(device_num, word_length, channel_num);
+    /* Word length is RESOLUTION_32_BIT */
+
+    i2s_master_configure(device_num,
+        word_select_size, NO_CLOCK_GATING, word_mode);
+    /* word select size is 32 bits,no clock gating */
+
+    i2s_set_rx_threshold(device_num, trigger_level, channel_num);
+    /* Interrupt trigger when FIFO level is 8 */
+
+    readl(&i2s[device_num]->channel[channel_num].ror);
+    readl(&i2s[device_num]->channel[channel_num].tor);
+
+    i2s_receive_channel_enable(device_num, channel_num, 1);
+}
+
+void i2s_tx_channel_configure(enum i2s_device_num_t device_num,
+    enum i2s_channel_num_t channel_num,
+    enum word_length_t word_length,
+    enum word_select_cycles_t word_select_size,
+    enum fifo_threshold_t trigger_level,
+    enum i2s_work_mode_t word_mode)
+{
+    writel(0, &i2s[device_num]->channel[channel_num].rer);
+    /* disable rx */
+
+    i2s_transmit_channel_enable(device_num, channel_num, 0);
+    /* Transmit channel disable */
+
+    writel(1, &i2s[device_num]->txffr);
+    /* flush tx fifo */
+    writel(1, &i2s[device_num]->channel[channel_num].tff);
+    /* flush individual fifo */
+
+    if (word_length == RESOLUTION_16_BIT)
+    {
+        i2s_transmit_dma_divide(I2S_DEVICE_0, 1);
+    }
+    i2s_set_tx_word_length(device_num, word_length, channel_num);
+    /* Word length is RESOLUTION_16_BIT */
+
+    i2s_master_configure(device_num, word_select_size, NO_CLOCK_GATING, word_mode);
+    /* word select size is 16 bits,gating after 16 bit */
+
+    i2s_set_tx_threshold(device_num, trigger_level, channel_num);
+    /* Interrupt trigger when FIFO level is 8 */
+
+    i2s_transmit_channel_enable(device_num, channel_num, 1);
+}
+
+int i2s_set_rx_word_length(enum i2s_device_num_t device_num,
+               enum word_length_t word_length,
+               enum i2s_channel_num_t channel_num)
+{
+    union rcr_tcr_u u_rcr;
+
+    if (word_length > RESOLUTION_32_BIT || word_length < IGNORE_WORD_LENGTH)
+        return -1;
+    if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
+        return -1;
+
+    u_rcr.reg_data = readl(&i2s[device_num]->channel[channel_num].rcr);
+    u_rcr.rcr_tcr.wlen = word_length;
+    writel(u_rcr.reg_data, &i2s[device_num]->channel[channel_num].rcr);
+    return 0;
+}
+
+int i2s_set_tx_word_length(enum i2s_device_num_t device_num,
+               enum word_length_t word_length,
+               enum i2s_channel_num_t channel_num)
+{
+    union rcr_tcr_u u_tcr;
+
+    if (word_length > RESOLUTION_32_BIT || word_length < IGNORE_WORD_LENGTH)
+        return -1;
+    if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
+        return -1;
+
+    u_tcr.reg_data = readl(&i2s[device_num]->channel[channel_num].tcr);
+    u_tcr.rcr_tcr.wlen = word_length;
+    writel(u_tcr.reg_data, &i2s[device_num]->channel[channel_num].tcr);
+    return 0;
+}
+
+int i2s_master_configure(enum i2s_device_num_t device_num,
+    enum word_select_cycles_t word_select_size,
+    enum sclk_gating_cycles_t gating_cycles,
+    enum i2s_work_mode_t word_mode)
+{
+    union ccr_u u_ccr;
+    union cer_u u_cer;
+
+    if (word_select_size < SCLK_CYCLES_16 ||
+        word_select_size > SCLK_CYCLES_32)
+        return -1;
+    if (gating_cycles < NO_CLOCK_GATING ||
+        gating_cycles > CLOCK_CYCLES_24)
+        return -1;
+
+    u_ccr.reg_data = readl(&i2s[device_num]->ccr);
+    u_ccr.ccr.clk_word_size = word_select_size;
+    u_ccr.ccr.clk_gate = gating_cycles;
+    u_ccr.ccr.align_mode = word_mode;
+    writel(u_ccr.reg_data, &i2s[device_num]->ccr);
+
+    u_cer.reg_data = readl(&i2s[device_num]->cer);
+    u_cer.cer.clken = 1;
+    writel(u_cer.reg_data, &i2s[device_num]->cer);
+    /* Clock generation enable */
+
+    return 0;
+}
+
+int i2s_set_rx_threshold(enum i2s_device_num_t device_num,
+             enum fifo_threshold_t threshold,
+             enum i2s_channel_num_t channel_num)
+{
+    union rfcr_u u_rfcr;
+
+    if (threshold < TRIGGER_LEVEL_1 || threshold > TRIGGER_LEVEL_16)
+        return -1;
+    if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
+        return -1;
+
+    u_rfcr.reg_data = readl(&i2s[device_num]->channel[channel_num].rfcr);
+    u_rfcr.rfcr.rxchdt = threshold;
+    writel(u_rfcr.reg_data, &i2s[device_num]->channel[channel_num].rfcr);
+
+    return 0;
+}
+
+int i2s_set_tx_threshold(enum i2s_device_num_t device_num,
+             enum fifo_threshold_t threshold,
+             enum i2s_channel_num_t channel_num)
+{
+    union tfcr_u u_tfcr;
+
+    if (threshold < TRIGGER_LEVEL_1 || threshold > TRIGGER_LEVEL_16)
+        return -1;
+    if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
+        return -1;
+
+    u_tfcr.reg_data = readl(&i2s[device_num]->channel[channel_num].tfcr);
+    u_tfcr.tfcr.txchet = threshold;
+    writel(u_tfcr.reg_data, &i2s[device_num]->channel[channel_num].tfcr);
+    return 0;
+}
+
+int i2s_set_mask_interrupt(enum i2s_device_num_t device_num,
+               enum i2s_channel_num_t channel_num,
+               uint32_t rx_available_int, uint32_t rx_overrun_int,
+               uint32_t tx_empty_int, uint32_t tx_overrun_int)
+{
+    union imr_u u_imr;
+
+    if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
+        return -1;
+    u_imr.reg_data = readl(&i2s[device_num]->channel[channel_num].imr);
+
+    if (rx_available_int == 1)
+        u_imr.imr.rxdam = 1;
+    else
+        u_imr.imr.rxdam = 0;
+    if (rx_overrun_int == 1)
+        u_imr.imr.rxfom = 1;
+    else
+        u_imr.imr.rxfom = 0;
+
+    if (tx_empty_int == 1)
+        u_imr.imr.txfem = 1;
+    else
+        u_imr.imr.txfem = 0;
+    if (tx_overrun_int == 1)
+        u_imr.imr.txfom = 1;
+    else
+        u_imr.imr.txfom = 0;
+    writel(u_imr.reg_data, &i2s[device_num]->channel[channel_num].imr);
+    return 0;
+}
+
+int i2s_receive_channel_enable(enum i2s_device_num_t device_num,
+    enum i2s_channel_num_t channel_num, uint32_t enable)
+{
+    union rer_u u_rer;
+
+    if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
+        return -1;
+    u_rer.reg_data = readl(&i2s[device_num]->channel[channel_num].rer);
+    u_rer.rer.rxchenx = enable;
+    writel(u_rer.reg_data, &i2s[device_num]->channel[channel_num].rer);
+    return 0;
+}
+
+int i2s_transmit_channel_enable(enum i2s_device_num_t device_num,
+    enum i2s_channel_num_t channel_num, uint32_t enable)
+{
+    union ter_u u_ter;
+
+    if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
+        return -1;
+
+    u_ter.reg_data = readl(&i2s[device_num]->channel[channel_num].ter);
+    u_ter.ter.txchenx = enable;
+    writel(u_ter.reg_data, &i2s[device_num]->channel[channel_num].ter);
+    return 0;
+}
+
+int i2s_transmit_dma_enable(enum i2s_device_num_t device_num, uint32_t enable)
+{
+    union ccr_u u_ccr;
+
+    if (device_num >= I2S_DEVICE_MAX)
+        return -1;
+
+    u_ccr.reg_data = readl(&i2s[device_num]->ccr);
+    u_ccr.ccr.dma_tx_en = enable;
+    writel(u_ccr.reg_data, &i2s[device_num]->ccr);
+
+    return 0;
+}
+
+int i2s_receive_dma_enable(enum i2s_device_num_t device_num, uint32_t enable)
+{
+    union ccr_u u_ccr;
+
+    if (device_num >= I2S_DEVICE_MAX)
+        return -1;
+
+    u_ccr.reg_data = readl(&i2s[device_num]->ccr);
+    u_ccr.ccr.dma_rx_en = enable;
+    writel(u_ccr.reg_data, &i2s[device_num]->ccr);
+
+    return 0;
+}
+
+int i2s_transmit_dma_divide(enum i2s_device_num_t device_num, uint32_t enable)
+{
+    union ccr_u u_ccr;
+
+    if (device_num >= I2S_DEVICE_MAX)
+        return -1;
+
+    u_ccr.reg_data = readl(&i2s[device_num]->ccr);
+    u_ccr.ccr.dma_divide_16 = enable;
+    writel(u_ccr.reg_data, &i2s[device_num]->ccr);
+
+    return 0;
+}
+
+int32_t i2s_receive_data(enum i2s_device_num_t device_num,
+      enum i2s_channel_num_t channel_num, uint64_t *buf,
+      uint32_t length)
+{
+    uint32_t i = 0;
+    union isr_u u_isr;
+
+    readl(&i2s[device_num]->channel[channel_num].ror);
+    /*clear over run*/
+
+    for (i = 0; i < length;)
+    {
+        u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr);
+        if (u_isr.isr.rxda == 1)
+        {
+            buf[i] = readl(&i2s[device_num]->channel[channel_num].left_rxtx);
+            buf[i] <<= 32;
+            buf[i++] |= readl(&i2s[device_num]->channel[channel_num].right_rxtx);
+        }
+    }
+    return 0;
+}
+
+int32_t i2s_receive_data_dma(enum i2s_device_num_t device_num, uint32_t *buf,
+    uint32_t length, dmac_channel_number channel_num)
+{
+    sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_num * 2);
+    dmac_set_single_mode(channel_num, (void *)(&i2s[device_num]->rxdma), /*pcm*/buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
+                          DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
+    dmac_wait_done(channel_num);
+    return 0;
+}
+
+int32_t i2s_recv_dma(enum i2s_device_num_t device_num, uint32_t *buf,
+    uint32_t length, dmac_channel_number channel_num)
+{
+    static uint8_t dmac_recv_flag[6] = {0,0,0,0,0,0};
+    if(dmac_recv_flag[channel_num])
+        dmac_wait_done(channel_num);
+    else
+        dmac_recv_flag[channel_num] = 1;
+    sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_num * 2);
+    dmac_set_single_mode(channel_num, (void *)(&i2s[device_num]->rxdma), /*pcm*/buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
+                          DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
+    return 0;
+}
+
+int32_t i2s_special_dma(enum i2s_device_num_t device_src_num, enum i2s_device_num_t device_dest_num,
+    uint32_t length, dmac_channel_number channel_num)
+{
+    static uint8_t dmac_recv_flag[6] = {0,0,0,0,0,0};
+    if(dmac_recv_flag[channel_num])
+        dmac_wait_done(channel_num);
+    else
+        dmac_recv_flag[channel_num] = 1;
+    sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_src_num * 2);
+    dmac_set_single_mode(channel_num, (void *)(&i2s[device_src_num]->rxdma), (void *)(&i2s[device_dest_num]->txdma), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE,
+                          DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
+    return 0;
+}
+
+int i2s_transmit_data(enum i2s_device_num_t device_num,
+    enum i2s_channel_num_t channel_num, uint8_t *pcm, uint32_t length, uint8_t single_length)
+{
+    union isr_u u_isr;
+    uint32_t left_buffer = 0;
+    uint32_t right_buffer = 0;
+    uint32_t i = 0;
+    uint32_t j = 0;
+    if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
+        return -1;
+
+    length = length / (single_length / 8) / 2; /* sample num */
+    readl(&i2s[device_num]->channel[channel_num].tor);
+    /* read clear overrun flag */
+
+    for (j = 0; j < length;)
+    {
+        u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr);
+        if (u_isr.isr.txfe == 1)
+        {
+            switch(single_length)
+            {
+                case 16:
+                    left_buffer = ((uint16_t *)pcm)[i++];
+                    right_buffer = ((uint16_t *)pcm)[i++];
+                    break;
+                case 24:
+                    left_buffer = 0;
+                    left_buffer |= pcm[i++];
+                    left_buffer |= pcm[i++] << 8;
+                    left_buffer |= pcm[i++] << 16;
+                    right_buffer = 0;
+                    right_buffer |= pcm[i++];
+                    right_buffer |= pcm[i++] << 8;
+                    right_buffer |= pcm[i++] << 16;
+                    break;
+                case 32:
+                    left_buffer = ((uint32_t *)pcm)[i++];
+                    right_buffer = ((uint32_t *)pcm)[i++];
+                    break;
+                default:
+                    left_buffer = pcm[i++];
+                    right_buffer = pcm[i++];
+                    break;
+            }
+            writel(left_buffer, &i2s[device_num]->channel[channel_num].left_rxtx);
+            writel(right_buffer, &i2s[device_num]->channel[channel_num].right_rxtx);
+            j++;
+        }
+    }
+    return 0;
+}
+
+int i2s_trans_data(enum i2s_device_num_t device_num,enum i2s_channel_num_t channel_num,
+    uint8_t *pcm, uint32_t length, uint8_t single_length, uint8_t track_num)
+{
+    union isr_u u_isr;
+    uint32_t left_buffer = 0;
+    uint32_t right_buffer = 0;
+    uint32_t i = 0;
+    uint32_t j = 0;
+    if (channel_num < CHANNEL_0 || channel_num > CHANNEL_3)
+        return -1;
+    readl(&i2s[device_num]->channel[channel_num].tor);
+    /* read clear overrun flag */
+
+    for (j = 0; j < length;)
+    {
+        u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr);
+        if (u_isr.isr.txfe == 1)
+        {
+            switch(single_length)
+            {
+                case 16:
+                    left_buffer = ((uint16_t *)pcm)[i++];
+                    track_num == 2 ? (right_buffer = ((uint16_t *)pcm)[i++]) : (right_buffer = 0);
+                    break;
+                case 24:
+                    left_buffer = 0;
+                    left_buffer |= pcm[i++];
+                    left_buffer |= pcm[i++] << 8;
+                    left_buffer |= pcm[i++] << 16;
+                    right_buffer = 0;
+                    if(track_num == 2)
+                    {
+                        right_buffer |= pcm[i++];
+                        right_buffer |= pcm[i++] << 8;
+                        right_buffer |= pcm[i++] << 16;
+                    }
+                    break;
+                case 32:
+                    left_buffer = ((uint32_t *)pcm)[i++];
+                    track_num == 2 ? (right_buffer = ((uint32_t *)pcm)[i++]) : (right_buffer = 0);
+                    break;
+                default:
+                    left_buffer = pcm[i++];
+                    track_num == 2 ? (right_buffer = pcm[i++]) : (right_buffer = 0);
+                    break;
+            }
+            writel(left_buffer, &i2s[device_num]->channel[channel_num].left_rxtx);
+            writel(right_buffer, &i2s[device_num]->channel[channel_num].right_rxtx);
+            j ++;
+        }
+    }
+    return 0;
+}
+
+int i2s_transmit_data_dma(enum i2s_device_num_t device_num,
+    void *pcm, uint32_t length, uint8_t single_length, dmac_channel_number channel_num)
+{
+    length = length / (single_length / 8) / 2;
+    sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_TX_REQ + device_num * 2);
+    dmac_set_single_mode(channel_num, pcm/*buf*/, (void *)(&i2s[device_num]->txdma), DMAC_ADDR_INCREMENT,
+                         DMAC_ADDR_NOCHANGE,DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
+    dmac_wait_done(channel_num);
+    return 0;
+}
+
+void i2s_send_data_dma(enum i2s_device_num_t device_num,
+    void *pcm, uint32_t length, dmac_channel_number channel_num)
+{
+    static uint8_t dmac_init_flag[6] = {0,0,0,0,0,0};
+    if(dmac_init_flag[channel_num])
+        dmac_wait_done(channel_num);
+    else
+        dmac_init_flag[channel_num] = 1;
+    sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_I2S0_TX_REQ + device_num * 2);
+    dmac_set_single_mode(channel_num, pcm, (void *)(&i2s[device_num]->txdma), DMAC_ADDR_INCREMENT,
+                         DMAC_ADDR_NOCHANGE, DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, length);
+}
+
+void parse_voice(uint32_t *buf, uint8_t *pcm, uint32_t length,  uint32_t bits_per_sample,
+    uint8_t track_num, uint32_t *send_len)
+{
+    uint32_t i,j=0;
+    *send_len = length * 2;
+    switch(bits_per_sample)
+    {
+        case 16:
+            i2s_transmit_dma_divide(I2S_DEVICE_0, 1);
+            for(i = 0; i < length; i++)
+            {
+                buf[i] = ((uint16_t *)pcm)[i];
+            }
+            *send_len = length;
+            break;
+        case 24:
+            for(i = 0; i < length; i++)
+            {
+                buf[2*i] = 0;
+                buf[2*i] |= pcm[j++];
+                buf[2*i] |= pcm[j++] << 8;
+                buf[2*i] |= pcm[j++] << 16;
+                buf[2*i+1] = 0;
+                if(track_num == 2)
+                {
+                    buf[2*i+1] |= pcm[j++];
+                    buf[2*i+1] |= pcm[j++] << 8;
+                    buf[2*i+1] |= pcm[j++] << 16;
+                }
+            }
+            break;
+        case 32:
+            for(i = 0; i < length; i++)
+            {
+                buf[2*i] = ((uint32_t *)pcm)[i];
+                buf[2*i+1] = 0;
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+int i2s_play(enum i2s_device_num_t device_num,dmac_channel_number channel_num,
+    uint8_t *buf, size_t length, uint32_t frame, uint32_t bits_per_sample, uint8_t track_num)
+{
+    uint32_t sample_cnt = length / ( bits_per_sample / 8 ) / track_num;
+    uint32_t frame_cnt = sample_cnt / frame;
+    uint32_t frame_remain = sample_cnt % frame;
+    uint32_t i;
+    uint8_t *trans_buf;
+
+    if (bits_per_sample == 16 && track_num == 2)
+    {
+        for (i = 0; i < frame_cnt; i++)
+        {
+            trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num;
+            i2s_send_data_dma(device_num,trans_buf, frame, channel_num);
+        }
+        if(frame_remain)
+        {
+            trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num;
+            i2s_send_data_dma(device_num, trans_buf, frame_remain, channel_num);
+        }
+    }
+    else if (bits_per_sample == 32 && track_num == 2)
+    {
+        for (i = 0; i < frame_cnt; i++)
+        {
+            trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num;
+            i2s_send_data_dma(device_num,trans_buf, frame * 2, channel_num);
+        }
+        if(frame_remain)
+        {
+            trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num;
+            i2s_send_data_dma(device_num, trans_buf, frame_remain * 2, channel_num);
+        }
+    }
+    else
+    {
+        uint32_t *buff[2];
+        buff[0] = malloc(frame * 2 * sizeof(uint32_t) * 2);
+        buff[1] = buff[0] + frame * 2;
+        uint8_t flag = 0;
+        uint32_t send_len = 0;
+        for (i = 0; i < frame_cnt; i++)
+        {
+            trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num;
+            parse_voice(buff[flag], trans_buf, frame, bits_per_sample, track_num, &send_len);
+            i2s_send_data_dma(device_num,buff[flag], send_len, channel_num);
+            flag = !flag;
+        }
+        if (frame_remain)
+        {
+            trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num;
+            parse_voice(buff[flag], trans_buf, frame_remain, bits_per_sample, track_num, &send_len);
+            i2s_send_data_dma(device_num, trans_buf, send_len, channel_num);
+        }
+        free(buff[0]);
+    }
+    return 0;
+}
+

+ 257 - 0
lib/drivers/include/aes.h

@@ -0,0 +1,257 @@
+/* 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.
+ */
+#ifndef _DRIVER_AES_H
+#define _DRIVER_AES_H
+
+#include <stdint.h>
+#include "env/encoding.h"
+#include "platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _aes_mode_ctl
+{
+    /* set the first bit and second bit 00:ecb; 01:cbc,10:aes_gcm */
+    uint32_t cipher_mode : 3;
+    /* [4:3]:00:128; 01:192; 10:256;11:reserved*/
+    uint32_t kmode : 2;
+    uint32_t endian : 6;
+    uint32_t stream_mode : 3;
+    uint32_t reserved : 18;
+} __attribute__((packed, aligned(4))) aes_mode_ctl;
+
+/**
+ * @brief       AES
+ */
+typedef struct _aes
+{
+    uint32_t aes_key[4];
+    /* 0: encrption ; 1: dencrption */
+    uint32_t encrypt_sel;
+    /**
+     * [1:0], Set the first bit and second bit 00:ecb; 01:cbc;
+     * 10,11:aes_gcm
+    */
+    aes_mode_ctl mode_ctl;
+    uint32_t aes_iv[4];
+    /* aes interrupt enable */
+    uint32_t aes_endian;
+    /* aes interrupt flag */
+    uint32_t aes_finish;
+    /* gcm add data begin address */
+    uint32_t dma_sel;
+    /* gcm add data end address */
+    uint32_t gb_aad_end_adr;
+    /* gcm plantext/ciphter text data begin address */
+    uint32_t gb_pc_ini_adr;
+    /* gcm plantext/ciphter text data end address */
+    uint32_t gb_pc_end_adr;
+    /* gcm plantext/ciphter text data */
+    uint32_t aes_text_data;
+    /* AAD data */
+    uint32_t aes_aad_data;
+    /**
+     * [1:0],00:check not finish; 01: check fail; 10: check success;11:
+     * reversed
+     */
+    uint32_t tag_chk;
+    /* data can input flag 1: data can input; 0 : data cannot input */
+    uint32_t data_in_flag;
+    /* gcm input tag for compare with the calculate tag */
+    uint32_t gcm_in_tag[4];
+    /* gcm plantext/ciphter text data */
+    uint32_t aes_out_data;
+    uint32_t gb_aes_en;
+    /* data can output flag 1: data ready 0: data not ready */
+    uint32_t data_out_flag;
+    /* allow tag input when use GCM */
+    uint32_t tag_in_flag;
+    uint32_t tag_clear;
+    uint32_t gcm_out_tag[4];
+    uint32_t aes_key_ext[4];
+} __attribute__((packed, aligned(4))) aes_t;
+
+enum aes_cipher_mod
+{
+    AES_ECB = 0,
+    AES_CBC = 1,
+    AES_GCM = 2,
+};
+
+enum aes_kmode
+{
+    AES_128 = 0,
+    AES_192 = 1,
+    AES_256 = 2,
+};
+
+enum aes_encrypt_sel
+{
+    AES_ENCRYPTION = 0,
+    AES_DECRYPTION = 1,
+};
+
+/**
+ * @brief       Aes initialize
+ *
+ * @param[in]   key_addr        Key address
+ * @param[in]   key_length      Key length
+ * @param[in]   aes_iv          Aes iv
+ * @param[in]   iv_length       Iv length
+ * @param[in]   aes_aad         Aes aad
+ * @param[in]   cipher_mod      Aes cipher mode
+ * @param[in]   encrypt_sel      Aes encrypt select
+ * @param[in]   add_size        Aad size
+ * @param[in]   data_size       Data size
+ *
+ * @return      result
+ *     - 1      Success
+ *     - Other  Fail
+ */
+int aes_init(uint8_t* key_addr, uint8_t key_length, uint8_t* aes_iv,
+    uint8_t iv_length, uint8_t* aes_aad, enum aes_cipher_mod cipher_mod,
+    enum aes_encrypt_sel encrypt_sel, uint32_t add_size, uint32_t data_size);
+
+/**
+ * @brief       Aes write aad data
+ *
+ * @param[in]   aad_data        Aes aad data
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int aes_write_aad(uint32_t aad_data);
+
+/**
+ * @brief       Aes write text data
+ *
+ * @param[in]   text_data       Aes aad data
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int aes_write_text(uint32_t text_data);
+
+/**
+ * @brief       Aes write tag
+ *
+ * @param[in]   text_data       Aes tag point
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int aes_write_tag(uint32_t* tag);
+
+/**
+ * @brief       Aes get data in flag
+ *
+ * @return      Data in flag
+ */
+int aes_get_data_in_flag(void);
+
+/**
+ * @brief       Aes get data out flag
+ *
+ * @return      Data out flag
+ */
+int aes_get_data_out_flag(void);
+
+/**
+ * @brief       Aes get tag in flag
+ *
+ * @return      Tag in flag
+ */
+int aes_get_tag_in_flag(void);
+
+/**
+ * @brief       Aes read out data
+ *
+ * @return      Out data
+ */
+uint32_t aes_read_out_data(void);
+
+/**
+ * @brief       Aes check tag
+ *
+ * @return      Tag check result
+ *     - 0      Check not finish
+ *     - 1      Check fail
+ *     - 2      Check success
+ */
+int aes_check_tag(void);
+
+/**
+ * @brief       Aes get gcm out tag
+ *
+ * @param[out]   l_tag      gcm out tag
+ *
+ * @return      Tag check result
+ *     - 1      Success
+ *     - Other  Fail
+ */
+int aes_get_tag(uint8_t* l_tag);
+
+/**
+ * @brief       Aes clear check tag
+ *
+ * @return      Tag check result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int aes_clear_chk_tag(void);
+
+/**
+ * @brief       Aes process
+ *
+ * @param[in]   aes_in_data         Aes in data
+ * @param[in]   aes_out_data        Aes out data
+ * @param[in]   data_size           Aes data size
+ * @param[in]   cipher_mod          Aes cipher mode
+ *
+ * @return      Tag check result
+ *     - 1      Success
+ *     - Other  Fail
+ */
+int aes_process(uint8_t* aes_in_data,
+    uint8_t* aes_out_data,
+    uint32_t data_size,
+    enum aes_cipher_mod cipher_mod);
+
+/**
+ * @brief       Aes check gcm tag
+ *
+ * @param[in]   aes_gcm_tag     Aes gcm tag
+ *
+ * @return      Tag check result
+ *     - 1      Success
+ *     - Other  Fail
+ */
+int aes_check_gcm_tag(uint32_t* aes_gcm_tag);
+
+/**
+ * @brief      Aes clock initialize
+ */
+void aes_clkinit();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_AES_H */

+ 329 - 0
lib/drivers/include/audio_bf.h

@@ -0,0 +1,329 @@
+/* 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.
+ */
+#ifndef _DRIVER_AUDIO_BF_H
+#define _DRIVER_AUDIO_BF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern volatile struct audio_bf_reg_t* const audio_bf;
+
+enum en_bf_dir
+{
+    BF_DIR0 = 0,
+    BF_DIR1,
+    BF_DIR2,
+    BF_DIR3,
+    BF_DIR4,
+    BF_DIR5,
+    BF_DIR6,
+    BF_DIR7,
+    BF_DIR8,
+    BF_DIR9,
+    BF_DIR10,
+    BF_DIR11,
+    BF_DIR12,
+    BF_DIR13,
+    BF_DIR14,
+    BF_DIR15,
+};
+
+struct audio_bf_ch_cfg_t
+{
+    /**
+     * BF unit sound channel enable control bits.
+     * Bit 'x' corresponds to enable bit for sound channel 'x' (x = 0, 1, 2,
+     * . . ., 7). BF sound channels are related with I2S host RX channels.
+     * BF sound channel 0/1 correspond to the left/right channel of I2S RX0;
+     * BF channel 2/3 correspond to left/right channels of I2S RX1; and
+     * things like that. 0x1: writing '1' to enable the corresponding BF
+     * sound channel. 0x0: writing '0' to close the corresponding BF sound
+     * channel.
+     */
+    uint32_t bf_sound_ch_en : 8;
+    /**
+     * Target direction select for valid voice output.
+     * When the source voice direaction searching is done, software can use
+     * this field to select one from 16 sound directions for the following
+     * voice recognition. 0x0: select sound direction 0;   0x1: select sound
+     * direction 1; . . . . . . 0xF: select sound direction 15.
+     */
+    uint32_t bf_target_dir : 4;
+    /**
+     * This is the audio sample gain factor. Using this gain factor to
+     * enhance or reduce the stength of the sum of at most 8 source
+     * sound channel outputs. This is a unsigned 11-bit fix-point number,
+     * bit 10 is integer part and bit 9~0 are the fractional part.
+     */
+    uint32_t audio_gain : 11;
+    uint32_t reserved1 : 1;
+    /**
+     * audio data source configure parameter. This parameter controls where
+     * the audio data source comes from. 0x0: audio data directly sourcing
+     * from audio_bf internal buffer; 0x1: audio data sourcing from
+     * FFT result buffer.
+     */
+    uint32_t data_src_mode : 1;
+    uint32_t reserved2 : 3;
+    /**
+     * write enable for bf_sound_ch_en parameter.
+     * 0x1: allowing updates made to 'bf_sound_ch_en'.
+     * Access Mode: write only
+     */
+    uint32_t we_bf_sound_ch_en : 1;
+    /**
+     * write enable for bf_target_dir parameter.
+     * 0x1: allowing updates made to 'bf_target_dir'.
+     * Access Mode: write only
+     */
+    uint32_t we_bf_target_dir : 1;
+    /**
+     * write enable for audio_gain parameter.
+     * 0x1: allowing updates made to 'audio_gain'.
+     * Access Mode: write only
+     */
+    uint32_t we_audio_gain : 1;
+    /**
+     * write enable for data_out_mode parameter.
+     * 0x1: allowing updates made to 'data_src_mode'.
+     */
+    uint32_t we_data_src_mode : 1;
+} __attribute__((packed, aligned(4)));
+
+struct audio_bf_ctl_t
+{
+    /**
+     * Sound direction searching enable bit.
+     * Software writes '1' to start sound direction searching function.
+     * When all the sound sample buffers are filled full, this bit is
+     * cleared by hardware (this sample buffers are used for direction
+     * detect only). 0x1: enable direction searching.
+     */
+    uint32_t bf_dir_search_en : 1;
+    /*
+     *use this parameter to reset all the control logic on direction search processing path.  This bit is self-clearing.
+     *  0x1: apply reset to direction searching control logic;
+     *  0x0: No operation.
+     */
+    uint32_t search_path_reset : 1;
+    uint32_t reserved : 2;
+    /**
+     * Valid voice sample stream generation enable bit.
+     * After sound direction searching is done, software can configure this
+     * bit to generate a stream of voice samples for voice recognition. 0x1:
+     * enable output of voice sample stream. 0x0: stop the voice samlpe
+     * stream output.
+     */
+    uint32_t bf_stream_gen_en : 1;
+    /*
+     *use this parameter to reset all the control logic on voice stream generating path.  This bit is self-clearing.
+     *  0x1: apply reset to voice stream generating control logic;
+     *  0x0: No operation.
+     */
+    uint32_t voice_gen_path_reset : 1;
+    /*
+     *use this parameter to switch to a new voice source direction.  Software write '1' here and hardware will automatically clear it.
+     *  0x1: write '1' here to request switching to new voice source direction.
+     */
+    uint32_t update_voice_dir : 1;
+
+    uint32_t reserved1 : 1;
+    //write enable for 'bf_dir_search_en' parameter.
+    uint32_t we_bf_dir_search_en : 1;
+    uint32_t we_search_path_rst : 1;
+    uint32_t we_bf_stream_gen : 1;
+    uint32_t we_voice_gen_path_rst : 1;
+    uint32_t we_update_voice_dir : 1;
+    uint32_t reserved2 : 19;
+
+} __attribute__((packed, aligned(4)));
+
+struct audio_bf_dir_bidx_t
+{
+    uint32_t dir_rd_idx0 : 6;
+    uint32_t reserved : 2;
+    uint32_t dir_rd_idx1 : 6;
+    uint32_t reserved1 : 2;
+    uint32_t dir_rd_idx2 : 6;
+    uint32_t reserved2 : 2;
+    uint32_t dir_rd_idx3 : 6;
+    uint32_t reserved3 : 2;
+} __attribute__((packed, aligned(4)));
+
+struct audio_bf_fir_coef_t
+{
+    uint32_t fir_tap0 : 16;
+    uint32_t fir_tap1 : 16;
+} __attribute__((packed, aligned(4)));
+
+struct audio_bf_dwsz_cfg_t
+{
+    /**
+     * TThe down-sizing ratio used for direction searching.
+     * 0x0: no down-sizing;
+     * 0x1: 1/2 down sizing;
+     * 0x2: 1/3 down sizing;
+     * . . . . . .
+     * 0xF: 1/16 down sizing.
+     */
+    uint32_t dir_dwn_siz_rate : 4;
+    /**
+     * The down-sizing ratio used for voice stream generation.
+     * 0x0: no down-sizing;
+     * 0x1: 1/2 down sizing;
+     * 0x2: 1/3 down sizing;
+     * . . . . . .
+     * 0xF: 1/16 down sizing.
+     */
+    uint32_t voc_dwn_siz_rate : 4;
+    /**
+     * This bit field is used to perform sample precision reduction when
+     * the source sound sample (from I2S0 host receiving channels)
+     * precision is 20/24/32 bits.
+     * 0x0: take bits 15~0 from the source sound sample;
+     * 0x1: take bits 16~1 from the source sound sample;
+     * 0x2: take bits 17~2 from the source sound sample;
+     * . . . . . .
+     * 0x10: take bits 31~16 from the source sound sample;
+     */
+    uint32_t smpl_shift_bits : 5;
+    uint32_t reserved : 19;
+} __attribute__((packed, aligned(4)));
+
+struct audio_bf_fft_cfg_t
+{
+    uint32_t fft_shift_factor : 9;
+    uint32_t reserved1 : 3;
+    uint32_t fft_enable : 1;
+    uint32_t reserved2 : 19;
+} __attribute__((packed, aligned(4)));
+
+struct audio_bf_int_stat_t
+{
+    /**
+     * sound direction searching data ready interrupt event.
+     * Writing '1' to clear this interrupt event.
+     * 0x1: data is ready for sound direction detect;
+     * 0x0: no event.
+     */
+    uint32_t dir_search_data_rdy : 1;
+    /**
+     * voice output stream buffer data ready interrupt event.
+     * When a block of 512 voice samples are collected, this interrupt event
+     * is asserted. Writing '1' to clear this interrupt event. 0x1: voice
+     * output stream buffer data is ready; 0x0: no event.
+     */
+    uint32_t voc_buf_data_rdy : 1;
+    uint32_t reserved : 30;
+} __attribute__((packed, aligned(4)));
+
+struct audio_bf_int_mask_t
+{
+    /**
+     * This is the interrupt mask to dir searching data ready interrupt.
+     * 0x1: mask off this interrupt;
+     * 0x0: enable this interrupt.
+     */
+    uint32_t dir_data_rdy_msk : 1;
+    /**
+     * This is the interrupt mask to voice output stream buffer ready
+     * interrupt. 0x1: mask off this interrupt; 0x0: enable this interrupt.
+     */
+    uint32_t voc_buf_rdy_msk : 1;
+    uint32_t reserved : 30;
+} __attribute__((packed, aligned(4)));
+
+struct audio_bf_reg_t
+{
+    /* 0x200 */
+    struct audio_bf_ch_cfg_t bf_ch_cfg_reg;
+    /* 0x204 */
+    struct audio_bf_ctl_t bf_ctl_reg;
+    /* 0x208 */
+    struct audio_bf_dir_bidx_t bf_dir_bidx[16][2];
+    /* 0x288 */
+    struct audio_bf_fir_coef_t bf_pre_fir0_coef[9];
+    /* 0x2ac */
+    struct audio_bf_fir_coef_t bf_post_fir0_coef[9];
+    /* 0x2d0 */
+    struct audio_bf_fir_coef_t bf_pre_fir1_coef[9];
+    /* 0x2f4 */
+    struct audio_bf_fir_coef_t bf_post_fir1_coef[9];
+    /* 0x318 */
+    struct audio_bf_dwsz_cfg_t bf_dwsz_cfg_reg;
+    /* 0x31c */
+    struct audio_bf_fft_cfg_t bf_fft_cfg_reg;
+    /* 0x320 */
+    /**
+     * This is the read register for system DMA to read data stored in
+     * sample out buffers (the sample out buffers are used for sound
+     * direction detect). Each data contains two sound samples.
+     */
+    volatile uint32_t sobuf_dma_rdata;
+    /* 0x324 */
+    /**
+     * This is the read register for system DMA to read data stored in voice
+     * out buffers (the voice out buffers are used for voice recognition).
+     * Each data contains two sound samples.
+     */
+    volatile uint32_t vobuf_dma_rdata;
+    /* 0x328 */
+    struct audio_bf_int_stat_t bf_int_stat_reg;
+    /* 0x32c */
+    struct audio_bf_int_mask_t bf_int_mask_reg;
+    /* 0x330 */
+    uint32_t saturation_counter;
+    /* 0x334 */
+    uint32_t saturation_limits;
+} __attribute__((packed, aligned(4)));
+
+void audio_bf_set_audio_gain(uint16_t gain);
+void audio_bf_set_smpl_shift(uint8_t smpl_shift);
+uint8_t audio_bf_get_smpl_shift(void);
+void audio_bf_set_channel_enabled(uint8_t channel_bit);
+void audio_bf_set_direction_delay(uint8_t dir_num, uint8_t* dir_bidx);
+void audio_bf_set_fft_shift_factor(uint8_t enable_flag, uint16_t shift_factor);
+void audio_bf_set_down_size(uint8_t dir_dwn_siz, uint8_t voc_dwn_siz);
+void audio_bf_set_interrupt_mask(uint8_t dir_int_mask, uint8_t voc_int_mask);
+
+void audio_bf_dir_enable(void);
+void audio_bf_dir_reset(void);
+void audio_bf_dir_set_prev_fir(uint16_t* fir_coef);
+void audio_bf_dir_set_post_fir(uint16_t* fir_coef);
+void audio_bf_dir_set_down_size(uint8_t dir_dwn_size);
+void audio_bf_dir_set_interrupt_mask(uint8_t dir_int_mask);
+void audio_bf_dir_clear_int_state(void);
+
+void audio_bf_voc_enable(uint8_t enable_flag);
+void audio_bf_voc_reset(void);
+void audio_bf_voc_set_direction(enum en_bf_dir direction);
+void audio_bf_voc_set_prev_fir(uint16_t* fir_coef);
+void audio_bf_voc_set_post_fir(uint16_t* fir_coef);
+void audio_bf_voc_set_down_size(uint8_t voc_dwn_size);
+void audio_bf_voc_set_interrupt_mask(uint8_t voc_int_mask);
+void audio_bf_voc_clear_int_state(void);
+void audio_bf_voc_reset_saturation_counter(void);
+uint32_t audio_bf_voc_get_saturation_counter(void);
+void audio_bf_voc_set_saturation_limit(uint16_t upper, uint16_t bottom);
+uint32_t audio_bf_voc_get_saturation_limit(void);
+
+void audio_bf_print_setting(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_AUDIO_BF_H */

+ 323 - 0
lib/drivers/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
+ * @brief      The CLINT block holds memory-mapped control and status registers
+ *             associated with local interrupts for a Coreplex.
+ *
+ * @note       CLINT RAM Layout
+ *
+ * | Address   -| Description                     |
+ * |------------|---------------------------------|
+ * | 0x02000000 | msip for hart 0                 |
+ * | 0x02000004 | msip for hart 1                 |
+ * | ...        | ...                             |
+ * | 0x02003FF8 | msip for hart 4094              |
+ * |            |                                 |
+ * | 0x02004000 | mtimecmp for hart 0             |
+ * | 0x02004008 | mtimecmp for hart 1             |
+ * | ...        | ...                             |
+ * | 0x0200BFF0 | mtimecmp For hart 4094          |
+ * | 0x0200BFF8 | mtime                           |
+ * |            |                                 |
+ * | 0x0200C000 | Reserved                        |
+ * | ...        | ...                             |
+ * | 0x0200EFFC | Reserved                        |
+ */
+
+#ifndef _DRIVER_CLINT_H
+#define _DRIVER_CLINT_H
+
+#include <stddef.h>
+#include <stdint.h>
+#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_HARTS     (4095)
+/* Real number of cores */
+#define CLINT_NUM_HARTS     (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-hart 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 hart’s mip register. Other bits in
+ *              the msip registers are hardwired to zero. The mapping supports
+ *              up to 4095 machine-mode harts.
+ */
+struct clint_msip_t
+{
+    uint32_t msip : 1;  /*!< Bit 0 is msip */
+    uint32_t zero : 31; /*!< Bits [32:1] is 0 */
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Timer compare Registers Machine-mode timer interrupts are
+ *              generated by a real-time counter and a per-hart 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 hart’s time comparator. A timer interrupt is pending
+ *              whenever mtime is greater than or equal to the value in a
+ *              hart’s mtimecmp register. The timer interrupt is reflected in
+ *              the mtip bit of the associated hart’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.
+ */
+struct clint_t
+{
+    /* 0x0000 to 0x3FF8, MSIP Registers */
+    struct clint_msip_t msip[CLINT_MAX_HARTS];
+    /* Resverd space, do not use */
+    uint32_t resv0;
+    /* 0x4000 to 0xBFF0, Timer Compare Registers */
+    clint_mtimecmp_t mtimecmp[CLINT_MAX_HARTS];
+    /* 0xBFF8, Time Register */
+    clint_mtime_t mtime;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Clint object instanse
+ */
+extern volatile struct 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);
+
+/**
+ * @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_deregister(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 hart id
+ *
+ * @param[in]   hart_id  The hart identifier
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int clint_ipi_send(size_t hart_id);
+
+/**
+ * @brief       Clear local interprocessor interrupt
+ *
+ * @param[in]   hart_id  The hart identifier
+ *
+ * @return      result
+ *     - 1      An IPI was pending
+ *     - 0      Non IPI was pending
+ *     - -1     Fail
+ */
+int clint_ipi_clear(size_t hart_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_deregister(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_CLINT_H */
+

+ 357 - 0
lib/drivers/include/common.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.
+ */
+#ifndef _DRIVER_COMMON_H
+#define _DRIVER_COMMON_H
+
+#ifdef __cplusplus
+#include <cstdbool>
+#include <cstddef>
+#include <cstdint>
+#else /* __cplusplus */
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#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", __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);
+
+/**
+ * @brief       Enable interrupt
+ */
+void machine_irq_enable();
+
+/**
+ * @brief       Disable interrupt
+ */
+void machine_irq_disable();
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _DRIVER_COMMON_H */
+

+ 1686 - 0
lib/drivers/include/dmac.h

@@ -0,0 +1,1686 @@
+/* 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.
+ */
+#ifndef _DRIVER_DMAC_H
+#define _DRIVER_DMAC_H
+
+#include <stdint.h>
+#include "io.h"
+#include "platform.h"
+#include "stdbool.h"
+
+#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;
+
+typedef enum _dmac_src_dst_select
+{
+    DMAC_SRC = 0x1,
+    DMAC_DST = 0x2,
+    DMAC_SRC_DST = 0x3
+} dmac_src_dst_select;
+
+typedef enum _state_value
+{
+    clear = 0,
+    set = 1
+} state_value;
+
+enum dmac_lock_bus_ch
+{
+    DMAC_LOCK_BUS     = 0x1,
+    DMAC_LOCK_CHANNEL = 0x2,
+    DMAC_LOCK_BUS_CH  = 0x3
+};
+
+enum dmac_sw_hw_hs_select
+{
+    DMAC_HS_HARDWARE = 0x0,
+    DMAC_HS_SOFTWARE = 0x1
+};
+
+enum dmac_scatter_gather_param
+{
+    DMAC_SG_COUNT = 0x0,
+    DMAC_SG_INTERVAL = 0x1
+};
+
+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
+};
+
+enum dmac_software_req
+{
+    /* ReqSrcReq/ReqDstReq */
+    DMAC_REQUEST    = 0x1,
+    /* SglReqSrcReq/SglReqDstReq */
+    DMAC_SINGLE_REQUEST = 0x2,
+    /* LstReqSrcReq/LstReqDstReq */
+    DMAC_LAST_REQUEST   = 0x4
+};
+
+enum dmac_master_number
+{
+    DMAC_MASTER1 = 0x0,
+    DMAC_MASTER2 = 0x1
+};
+
+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
+};
+
+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
+};
+
+enum dmac_address_increment
+{
+    DMAC_ADDR_INCREMENT = 0x0,
+    DMAC_ADDR_NOCHANGE  = 0x1
+};
+
+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
+};
+
+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
+};
+
+enum dmac_multiblk_transfer_type
+{
+    CONTIGUOUS     = 0,
+    RELOAD   = 1,
+    SHADOWREGISTER = 2,
+    LINKEDLIST     = 3
+};
+
+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
+};
+
+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
+};
+
+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
+};
+
+enum dmac_fifo_mode
+{
+    DMAC_FIFO_MODE_SINGLE = 0x0,
+    DMAC_FIFO_MODE_HALF = 0x1
+};
+
+enum dw_dmac_flow_ctl_mode
+{
+    DMAC_DATA_PREFETCH_ENABLED  = 0x0,
+    DMAC_DATA_PREFETCH_DISABLED = 0x1
+};
+
+enum dmac_polarity_level
+{
+    DMAC_ACTIVE_HIGH = 0x0,
+    DMAC_ACTIVE_LOW = 0x1
+};
+
+enum dmac_lock_level
+{
+    DMAC_LOCK_LEVEL_DMA_TRANSFER   = 0x0,
+    DMAC_LOCK_LEVEL_BLOCK_TRANSFER = 0x1,
+    DMAC_LOCK_LEVEL_TRANSACTION    = 0x2
+};
+
+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
+};
+
+enum dmac_state
+{
+    ZERO,
+    ONE
+};
+
+enum dmca_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
+};
+
+struct dmac_cfg_t
+{
+    /**
+     * 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)));
+
+union dmac_cfg_u
+{
+    struct dmac_cfg_t cfg;
+    uint64_t data;
+};
+
+struct damc_chen_t
+{
+    /**
+     * 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)));
+
+union dmac_chen_u
+{
+    struct damc_chen_t dmac_chen;
+    uint64_t data;
+};
+
+struct dmac_intstatus_t
+{
+    /**
+     * 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)));
+
+union dmac_intstatus_u
+{
+    struct dmac_intstatus_t intstatus;
+    uint64_t data;
+};
+
+struct dmac_commonreg_intclear_t
+{
+    /**
+     * 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)));
+
+union dmac_commonreg_intclear_u
+{
+    struct dmac_commonreg_intclear_t com_intclear;
+    uint64_t data;
+};
+
+struct dmac_commonreg_intstatus_enable_t
+{
+    /**
+     * 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)));
+
+union dmac_commonreg_intstatus_enable_u
+{
+    struct dmac_commonreg_intstatus_enable_t intstatus_enable;
+    uint64_t data;
+};
+
+struct dmac_commonreg_intsignal_enable_t
+{
+    /**
+     * 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)));
+
+union dmac_commonreg_intsignal_enable_u
+{
+    struct dmac_commonreg_intsignal_enable_t intsignal_enable;
+    uint64_t data;
+};
+
+struct dmac_commonreg_intstatus_t
+{
+    /**
+     * 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)));
+
+union dmac_commonreg_intstatus_u
+{
+    struct dmac_commonreg_intstatus_t commonreg_intstatus;
+    uint64_t data;
+};
+
+struct dmac_reset_t
+{
+    /* Bit 0 is DMAC reset request bit */
+    uint64_t rst : 1;
+    /* Bits [63:1] is reserved */
+    uint64_t rsvd : 63;
+} __attribute__((packed, aligned(8)));
+
+union dmac_reset_u
+{
+    struct dmac_reset_t reset;
+    uint64_t data;
+};
+
+struct dmac_ch_block_ts_t
+{
+    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)));
+
+union dmac_ch_block_ts_u
+{
+    struct dmac_ch_block_ts_t block_ts;
+    uint64_t data;
+};
+
+struct dmac_ch_ctl_t
+{
+    /**
+     * 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)));
+
+union dmac_ch_ctl_u
+{
+    struct dmac_ch_ctl_t ch_ctl;
+    uint64_t data;
+};
+
+struct dmac_ch_cfg_t
+{
+    /**
+     * 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)));
+
+union dmac_ch_cfg_u
+{
+    struct dmac_ch_cfg_t ch_cfg;
+    uint64_t data;
+};
+
+struct dmac_ch_llp_t
+{
+    /**
+     * 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)));
+
+union dmac_ch_llp_u
+{
+    struct dmac_ch_llp_t llp;
+    uint64_t data;
+};
+
+struct dmac_ch_status_t
+{
+    /* 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)));
+
+union dmac_ch_status_u
+{
+    struct dmac_ch_status_t status;
+    uint64_t data;
+};
+
+struct dmac_ch_swhssrc_t
+{
+    /**
+     * 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)));
+
+union dmac_ch_swhssrc_u
+{
+    struct dmac_ch_swhssrc_t swhssrc;
+    uint64_t data;
+};
+
+struct dmac_ch_swhsdst_t
+{
+    /**
+     * 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)));
+
+union dmac_ch_swhsdst_u
+{
+    struct dmac_ch_swhsdst_t swhsdst;
+    uint64_t data;
+};
+
+struct dmac_ch_blk_tfr_resumereq_t
+{
+    /**
+     * 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)));
+
+union dmac_ch_blk_tfr_resumereq_u
+{
+    struct dmac_ch_blk_tfr_resumereq_t blk_tfr_resumereq;
+    uint64_t data;
+};
+
+struct dmac_ch_intstatus_enable_t
+{
+    /* 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;
+};
+
+union dmac_ch_intstatus_enable_u
+{
+    struct dmac_ch_intstatus_enable_t ch_intstatus_enable;
+    uint64_t data;
+};
+
+struct dmac_ch_intclear_t
+{
+    /* 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)));
+
+union dmac_ch_intclear_u
+{
+    uint64_t data;
+    struct dmac_ch_intclear_t intclear;
+};
+
+struct dmac_channel_t
+{
+    /* (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)));
+
+struct dmac_t
+{
+    /* (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];
+    struct dmac_channel_t channel[DMAC_CHANNEL_COUNT];
+} __attribute__((packed, aligned(8)));
+
+struct dmac_channel_config_t
+{
+    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;
+};
+
+#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()
+ */
+struct dmac_lli_item_t
+{
+    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)));
+
+extern volatile struct dmac_t *const dmac;
+
+/**
+ * @brief       Dmac initialize
+ */
+void dmac_init(void);
+
+/**
+ * @brief       Read dmac id
+ *
+ * @return      Dmac id
+ */
+uint64_t dmac_read_id(void);
+
+/**
+ * @brief       Read dmac component version
+ *
+ * @return      Dmac version
+ */
+uint64_t dmac_read_version(void);
+
+/**
+ * @brief       Read AXI channel id
+ *
+ * @param[in]   channel_num  The channel number
+ *
+ * @return      channel AXI ID data
+ */
+uint64_t dmac_read_channel_id(dmac_channel_number ch);
+
+/**
+ * @brief       Set channle configure
+ *
+ * @param[in]   channel_num     The channel number
+ * @param[in]   cfg_param       The configuration parameter
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int dmac_set_channel_config(dmac_channel_number channel_num,
+    struct dmac_channel_config_t *cfg_param);
+
+/**
+ * @brief       Get channel configure param
+ *
+ * @param[in]   channel_num     The channel number
+ * @param[out]  cfg_param       The configuration parameter
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int dmac_get_channel_config(dmac_channel_number channel_num,
+    struct dmac_channel_config_t *cfg_param);
+
+/**
+ * @brief       Enable dmac source transaction complete interrupt
+ *
+ * @param[in]   channel_num     The channel number
+ */
+void src_transaction_complete_int_enable(dmac_channel_number channel_num);
+
+/**
+ * @brief       Enable dmac channel
+ *
+ * @param[in]   channel_num     The channel number
+ */
+void dmac_channel_enable(dmac_channel_number channel_num);
+
+/**
+ * @brief       Enable dmac
+ */
+void dmac_enable(void);
+
+/**
+ * @brief       Enable dmac channel interrupt status
+ *
+ * @param[in]   channel_num     The channel number
+ */
+void dmac_enable_channel_interrupt_status(dmac_channel_number channel_num);
+
+/**
+ * @brief       Disable dmac channel interrupt status
+ *
+ * @param[in]   channel_num     The channel number
+ */
+void dmac_disable_channel_interrupt_status(dmac_channel_number channel_num);
+
+/**
+ * @brief       Check whether channel is busy
+ *
+ * @param[in]   channel_num     The channel number
+ *
+ * @return      result
+ *     - 0      Not busy
+ *     - 1      Busy
+ */
+int32_t dmac_check_channel_busy(dmac_channel_number channel_num);
+
+/**
+ * @brief       Clear interrupt status
+ *
+ * @param[in]   channel_num     The channel number
+ */
+void dmac_chanel_interrupt_clear(dmac_channel_number channel_num);
+
+/**
+ * @brief       Create link list item
+ *
+ * @param[in]   channel_num     The channel number
+ * @param[in]   LLI_row_num     The lli row number
+ * @param[in]   LLI_last_row    The lli last row
+ * @param[out]  lli_item        The lli item
+ * @param[in]   cfg_param       The configuration parameter
+ */
+void dmac_link_list_item(dmac_channel_number channel_num, uint8_t lli_row_num,
+    int8_t lli_last_row, struct dmac_lli_item_t *lli_item,
+    struct dmac_channel_config_t *cfg_param);
+
+/**
+ * @brief       linked list mode list addr entry,
+ *              descriptor table must be 64 byte aligned
+ *
+ * @param[in]   channel_num     The channel number
+ * @param[in]   addr            The address
+ */
+void dmac_set_linked_list_addr_point(dmac_channel_number channel_num,
+    uint64_t *addr);
+
+/**
+ * @brief       Set flow control
+ *
+ * @param[in]   channel_num     The channel number
+ * @param[in]   flow_control    The flow control
+ */
+void dmac_set_flow_control(dmac_channel_number channel_num,
+    enum dmac_transfer_flow flow_control);
+
+/**
+ * @brief       Set multitransfer type and handshake
+ *
+ * @param[in]   channel_num         The channel number
+ * @param[in]   transfer_type       The transfer type
+ * @param[in]   handshak_select     The handshake select
+ */
+void dmac_set_destination_transfer_control(dmac_channel_number channel_num,
+    enum dmac_multiblk_transfer_type transfer_type,
+    enum dmac_sw_hw_hs_select handshak_select);
+
+/**
+ * @brief       Set multitransfer type and handshak
+ *
+ * @param[in]   channel_num         The channel number
+ * @param[in]   transfer_type       The transfer type
+ * @param[in]   handshak_select     The handshake select
+ */
+void dmac_set_source_transfer_control(dmac_channel_number channel_num,
+    enum dmac_multiblk_transfer_type transfer_type,
+    enum dmac_sw_hw_hs_select handshak_select);
+
+/**
+ * @brief       Set destination's master,address mode, transfer width and transfer length
+ *
+ * @param[in]   channel_num         The channel number
+ * @param[in]   master_select       The master select
+ * @param[in]   address_mode        The address mode
+ * @param[in]   tr_width            The tr width
+ * @param[in]   burst_length        The burst length
+ */
+void dmac_master_control(dmac_channel_number channel_num,
+    enum dmac_master_number master_select,
+    enum dmac_address_increment address_mode,
+    enum dmac_transfer_width tr_width,
+    enum dmac_burst_trans_length burst_length);
+
+/**
+ * @brief       Set source's master,address mode, transfer width and transfer length
+ *
+ * @param[in]     channel_num       The channel number
+ * @param[in]     master_select     The master select
+ * @param[in]     address_mode      The address mode
+ * @param[in]     tr_width          The transfer width
+ * @param[in]     burst_length      The burst transfer length
+ */
+void dmac_source_control(dmac_channel_number channel_num,
+    enum dmac_master_number master_select,
+    enum dmac_address_increment address_mode,
+    enum dmac_transfer_width tr_width,
+    enum dmac_burst_trans_length burst_length);
+
+/**
+ * @brief       Set block transfer size
+ *
+ * @param[in]   channel_num     The channel number
+ * @param[in]   block_size      The block size
+ */
+void dmac_set_block_ts(dmac_channel_number channel_num, uint32_t block_size);
+
+/**
+ * @brief       Set dmac address
+ *
+ * @param[in]   channel_num     The channel number
+ * @param       src_addr        The source address
+ * @param       dst_src         The destination source
+ */
+void dmac_set_address(dmac_channel_number channel_num, uint64_t src_addr,
+    uint64_t dst_addr);
+
+/**
+ * @brief       Disable channel
+ *
+ * @param[in]   channel_num     The channel number
+ */
+void dmac_channel_disable(dmac_channel_number channel_num);
+
+/**
+ * @brief       Update dmac shadow register
+ *
+ * @param[in]   channel_num     The channel number
+ * @param[in]   last_block      The last block
+ * @param[in]   cfg_param       The configuration parameter
+ */
+void dmac_update_shandow_register(dmac_channel_number channel_num, int8_t last_block,
+    struct dmac_channel_config_t *cfg_param);
+
+/**
+ * @brief       Set shadow register invalid flag, used for first block transfer, after configure
+ *
+ * @param[in]   channel_num     The channel number
+ */
+void dmac_set_shadow_invalid_flag(dmac_channel_number channel_num);
+
+/**
+ * @brief       Set dmac channel parameters
+ *
+ * @param[in]   channel_num             The channel number
+ * @param[in]   src                     The source address
+ * @param[in]   dest                    The destination address
+ * @param[in]   src_inc                 Whether the source address auto increment
+ * @param[in]   dest_inc                Whether the destination address auto increment
+ * @param[in]   dmac_msize              The dmac burst transfer length
+ * @param[in]   dmac_trans_width        The dmac transfer width
+ * @param[in]   blockSize               The block size
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int dmac_set_channel_param(dmac_channel_number channel_num,
+    void *src, void *dest, enum dmac_address_increment src_inc, enum dmac_address_increment dest_inc,
+    enum dmac_burst_trans_length dmac_msize,
+    enum dmac_transfer_width dmac_trans_width,
+    uint32_t blockSize);
+
+/**
+ * @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_msize              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 channel_num,
+    void *src, void *dest, enum dmac_address_increment src_inc, enum dmac_address_increment dest_inc,
+    enum dmac_burst_trans_length dmac_msize,
+    enum dmac_transfer_width dmac_trans_width,
+    uint32_t blockSize);
+
+/**
+ * @brief       Wait for dmac work done
+ *
+ * @param[in]   channel_num  Dmac channel
+ *
+ */
+void dmac_wait_done(dmac_channel_number channel_num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_DMAC_H */

+ 284 - 0
lib/drivers/include/dvp.h

@@ -0,0 +1,284 @@
+/* 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.
+ */
+#ifndef _DRIVER_DVP_H
+#define _DRIVER_DVP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clang-format off */
+/**
+ * @brief       DVP object
+ */
+struct dvp_t
+{
+    volatile uint32_t dvp_cfg;
+    volatile uint32_t r_addr;
+    volatile uint32_t g_addr;
+    volatile uint32_t b_addr;
+    volatile uint32_t cmos_cfg;
+    volatile uint32_t sccb_cfg;
+    volatile uint32_t sccb_ctl;
+    volatile uint32_t axi;
+    volatile uint32_t sts;
+    volatile uint32_t reverse;
+    volatile uint32_t rgb_addr;
+} __attribute__((packed, aligned(4)));
+
+/* DVP Config Register */
+#define DVP_CFG_START_INT_ENABLE                0x00000001
+#define DVP_CFG_FINISH_INT_ENABLE               0x00000002
+#define DVP_CFG_AI_OUTPUT_ENABLE                0x00000004
+#define DVP_CFG_DISPLAY_OUTPUT_ENABLE           0x00000008
+#define DVP_CFG_AUTO_ENABLE                     0x00000010
+#define DVP_CFG_BURST_SIZE_4BEATS               0x00000100
+#define DVP_CFG_FORMAT_MASK                     0x00000600
+#define DVP_CFG_RGB_FORMAT                      0x00000000
+#define DVP_CFG_YUV_FORMAT                      0x00000200
+#define DVP_CFG_Y_FORMAT                        0x00000600
+#define DVP_CFG_HREF_BURST_NUM_MASK             0x000FF000
+#define DVP_CFG_HREF_BURST_NUM(x)               ((x) << 12)
+#define DVP_CFG_LINE_NUM_MASK                   0x3FF00000
+#define DVP_CFG_LINE_NUM(x)                     ((x) << 20)
+
+/* DVP CMOS Config Register */
+#define DVP_CMOS_CLK_DIV_MASK                   0x000000FF
+#define DVP_CMOS_CLK_DIV(x)                     ((x) << 0)
+#define DVP_CMOS_CLK_ENABLE                     0x00000100
+#define DVP_CMOS_RESET                          0x00010000
+#define DVP_CMOS_POWER_DOWN                     0x01000000
+
+/* DVP SCCB Config Register */
+#define DVP_SCCB_BYTE_NUM_MASK                  0x00000003
+#define DVP_SCCB_BYTE_NUM_2                     0x00000001
+#define DVP_SCCB_BYTE_NUM_3                     0x00000002
+#define DVP_SCCB_BYTE_NUM_4                     0x00000003
+#define DVP_SCCB_SCL_LCNT_MASK                  0x0000FF00
+#define DVP_SCCB_SCL_LCNT(x)                    ((x) << 8)
+#define DVP_SCCB_SCL_HCNT_MASK                  0x00FF0000
+#define DVP_SCCB_SCL_HCNT(x)                    ((x) << 16)
+#define DVP_SCCB_RDATA_BYTE(x)                  ((x) >> 24)
+
+/* DVP SCCB Control Register */
+#define DVP_SCCB_WRITE_ENABLE                   0x00000001
+#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                    0x000000FF
+#define DVP_AXI_GM_MLEN_1BYTE                   0x00000000
+#define DVP_AXI_GM_MLEN_4BYTE                   0x00000003
+
+/* DVP STS Register */
+#define DVP_STS_FRAME_START                     0x00000001
+#define DVP_STS_FRAME_START_WE                  0x00000002
+#define DVP_STS_FRAME_FINISH                    0x00000100
+#define DVP_STS_FRAME_FINISH_WE                 0x00000200
+#define DVP_STS_DVP_EN                          0x00010000
+#define DVP_STS_DVP_EN_WE                       0x00020000
+#define DVP_STS_SCCB_EN                         0x01000000
+#define DVP_STS_SCCB_EN_WE                      0x02000000
+/* clang-format on */
+
+/**
+ * @brief       DVP object instance
+ */
+extern volatile struct dvp_t* const dvp;
+
+/**
+ * @brief       Initialize DVP
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int dvp_init(uint8_t reglen);
+
+/**
+ * @brief       Set image format
+ *
+ * @param[in]   format      The image format
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int 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
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int 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
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int 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
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int dvp_set_display_addr(uint32_t addr);
+
+/**
+ * @brief       The frame start transfer
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int dvp_frame_start(void);
+
+/**
+ * @brief       The DVP convert start
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+void dvp_convert_start(void);
+
+/**
+ * @brief       The DVP convert finish
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int dvp_convert_finish(void);
+
+/**
+ * @brief       Get the image data
+ *
+ * @note        The image data stored in the address of RGB
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int dvp_get_image(void);
+
+/**
+ * @brief       Use SCCB write register
+ *
+ * @param[in]   dev_addr        The device address
+ * @param[in]   reg_addr        The register address
+ * @param[in]   reg_data        The register data
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int dvp_sccb_write(uint8_t dev_addr, uint16_t reg_addr, uint8_t reg_data);
+
+/**
+ * @brief       Use SCCB read register
+ *
+ * @param[in]   dev_addr        The device address
+ * @param[in]   reg_addr        The register address
+ *
+ * @return      The register value
+ */
+uint8_t dvp_sccb_read(uint8_t dev_addr, uint16_t reg_addr);
+
+/**
+ * @brief       Enable dvp burst
+ */
+void dvp_burst_enable(void);
+
+/**
+ * @brief       Disable dvp burst
+ */
+void dvp_burst_disable(void);
+
+/**
+ * @brief       Enable or disable dvp interrupt
+ *
+ * @param[in]   interrupt       Dvp interrupt
+ * @param[in]   status          0:disable 1:enable
+ *
+ */
+void dvp_interrupt_config(uint32_t interrupt, uint8_t status);
+
+/**
+ * @brief       Get dvp interrupt status
+ *
+ * @param[in]   interrupt       Dvp interrupt
+ *
+ *
+ * @return      Interrupt status
+ *     - 0      false
+ *     - 1      true
+ */
+int dvp_interrupt_get(uint32_t interrupt);
+
+/**
+ * @brief       Clear dvp interrupt status
+ *
+ * @param[in]   interrupt       Dvp interrupt
+ *
+ */
+void dvp_interrupt_clear(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(size_t index, int enable);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_DVP_H */

+ 980 - 0
lib/drivers/include/fpioa.h

@@ -0,0 +1,980 @@
+/* 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      Field Programmable GPIO Array (FPIOA)
+ *
+ *             The FPIOA peripheral supports the following features:
+ *
+ *             - 48 IO with 256 functions
+ *
+ *             - Schmitt trigger
+ *
+ *             - Invert input and output
+ *
+ *             - Pull up and pull down
+ *
+ *             - Driving selector
+ *
+ *             - Static input and output
+ *
+ */
+
+#ifndef _DRIVER_FPIOA_H
+#define _DRIVER_FPIOA_H
+
+#include <stdint.h>
+#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        | CLK_IN1          | Clock Input 1                     |
+ * | 21        | CLK_IN2          | Clock Input 2                     |
+ * | 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_PWND        | 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                        |
+ * | 222       | CONSTANT         | Constant function                 |
+ * | 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 */
+enum fpioa_function_e
+{
+    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_CLK_IN1          = 20, /*!< Clock Input 1 */
+    FUNC_CLK_IN2          = 21, /*!< Clock Input 2 */
+    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_PWND        = 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       = 219,    /*!< Internal function signal 13 */
+    FUNC_INTERNAL14       = 220,    /*!< Internal function signal 14 */
+    FUNC_INTERNAL15       = 221,    /*!< Internal function signal 15 */
+    FUNC_CONSTANT         = 222,    /*!< Constant function */
+    FUNC_INTERNAL16       = 223,    /*!< Internal function signal 16 */
+    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 */
+};
+/* 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 */
+enum fpioa_pull_e
+{
+    FPIOA_PULL_NONE,      /*!< No Pull */
+    FPIOA_PULL_DOWN,      /*!< Pull Down */
+    FPIOA_PULL_UP,        /*!< Pull Up */
+    FPIOA_PULL_MAX        /*!< Count of pull settings */
+};
+/* 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 */
+enum fpioa_driving_e
+{
+    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 */
+};
+/* 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.                    |
+ *
+ */
+struct fpioa_io_config_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 resv1 : 7;
+    /*!< Reserved bits. */
+    uint32_t pad_di : 1;
+    /*!< Read current IO's data input. */
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @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
+ *
+ */
+struct fpioa_tie_t
+{
+    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)));
+
+/**
+ * @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   |
+ *
+ */
+struct fpioa_t
+{
+    struct fpioa_io_config_t io[FPIOA_NUM_IO];
+    /*!< FPIOA GPIO multiplexer io array */
+    struct fpioa_tie_t tie;
+    /*!< FPIOA GPIO multiplexer tie */
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       FPIOA object instanse
+ */
+extern volatile struct 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 fpioa_init(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, struct 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, struct 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, enum fpioa_function_e 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 fpioa_set_function(int number, enum fpioa_function_e 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(enum fpioa_function_e 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(enum fpioa_function_e 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, enum fpioa_pull_e 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, enum fpioa_driving_e 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_func(enum fpioa_function_e function);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_FPIOA_H */
+

+ 176 - 0
lib/drivers/include/gpio.h

@@ -0,0 +1,176 @@
+/* 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.
+ */
+#ifndef _DRIVER_GPIO_H
+#define _DRIVER_GPIO_H
+
+#include "platform.h"
+#include <inttypes.h>
+#include <stddef.h>
+#include "gpio_common.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief       Structure for accessing GPIO registers by individual bit
+ */
+typedef struct
+{
+    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
+{
+    /* 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
+{
+    /* 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       Gpio pin initialize, map Pin number to Gpio function pin
+ *
+ * @param[in]   pin_num         Pin number
+ * @param[in]   gpio_pin        Gpio pin
+ */
+void gpio_pin_init(size_t pin_num, size_t gpio_pin);
+
+/**
+ * @brief       Set Gpio drive mode
+ *
+ * @param[in]   pin         Gpio pin
+ * @param[in]   mode        Gpio pin drive mode
+ */
+void gpio_set_drive_mode(size_t pin, gpio_drive_mode 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 gpio_get_pin_value(size_t pin);
+
+/**
+ * @brief       Set Gpio pin value
+ *
+ * @param[in]   pin         Gpio pin
+ * @param[in]   value       Gpio pin value
+ */
+void gpio_set_pin_value(size_t pin, gpio_pin_value value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_GPIO_H */
+

+ 53 - 0
lib/drivers/include/gpio_common.h

@@ -0,0 +1,53 @@
+/* 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.
+ */
+#ifndef _GPIO_COMMON_H
+#define _GPIO_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum
+{
+    GPIO_DM_Input,
+    GPIO_DM_InputPullDown,
+    GPIO_DM_InputPullUp,
+    GPIO_DM_Output,
+    GPIO_DM_OutputOpenDrain,
+    GPIO_DM_OutputOpenDrainPullUp,
+    GPIO_DM_OutputOpenSource,
+    GPIO_DM_OutputOpenSourcePullDown
+} gpio_drive_mode;
+
+typedef enum
+{
+    GPIO_PE_None,
+    GPIO_PE_Falling,
+    GPIO_PE_Rising,
+    GPIO_PE_Both
+} gpio_pin_edge;
+
+typedef enum
+{
+    GPIO_PV_Low,
+    GPIO_PV_High
+} gpio_pin_value;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GPIO_COMMON_H */
+

+ 267 - 0
lib/drivers/include/gpiohs.h

@@ -0,0 +1,267 @@
+/* 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.
+ */
+#ifndef _DRIVER_GPIOHS_H
+#define _DRIVER_GPIOHS_H
+
+#include <stdint.h>
+#include "platform.h"
+#include <stddef.h>
+#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
+ */
+struct gpiohs_raw_t
+{
+    /* 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)));
+
+/**
+ * @brief       GPIO bits object
+ */
+typedef struct
+{
+    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
+{
+    /* 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
+{
+    /* 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       Gpiohs initialize
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int gpiohs_init(void);
+
+/**
+ * @brief       Gpiohs pin initialize, map Pin number to Gpio function pin
+ *
+ * @param[in]   pin_num         Pin number
+ * @param[in]   gpio_pin        Gpiohs pin
+ */
+void gpiohs_pin_init(size_t pin_num, size_t gpio_pin);
+
+/**
+ * @brief       Set Gpiohs drive mode
+ *
+ * @param[in]   pin         Gpiohs pin
+ * @param[in]   mode        Gpiohs pin drive mode
+ */
+void gpiohs_set_drive_mode(size_t pin, gpio_drive_mode 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 gpiohs_get_pin_value(size_t pin);
+
+/**
+ * @brief      Set Gpiohs pin value
+ *
+ * @param[in]   pin      Gpiohs pin
+ * @param[in]   value    Gpiohs pin value
+ */
+void gpiohs_set_pin_value(size_t pin, gpio_pin_value 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(size_t pin, gpio_pin_edge 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(size_t pin, uint32_t priority, void(*func)());
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_GPIOHS_H */
+

+ 271 - 0
lib/drivers/include/hard_fft.h

@@ -0,0 +1,271 @@
+/* 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.
+ */
+#ifndef _DRIVER_HARD_FFT_H
+#define _DRIVER_HARD_FFT_H
+
+#include <stdint.h>
+#include "platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct complex
+{
+    float real;
+    float imag;
+} complex;
+
+typedef struct
+{
+    int16_t I1;
+    int16_t R1;
+    int16_t I2;
+    int16_t R2;
+} fft_data;
+
+typedef enum fft_point_e
+{
+    FFT_N512,
+    FFT_N256,
+    FFT_N128,
+    FFT_N64,
+} fft_point_t;
+
+typedef enum fft_mode_e
+{
+    IFFT_MODE,
+    FFT_MODE,
+} fft_mode_t;
+
+
+/**
+ * @brief      FFT algorithm accelerator register
+ *
+ * @note       FFT algorithm accelerator register table
+ *
+ * | Offset    | Name           | Description                         |
+ * |-----------|----------------|-------------------------------------|
+ * | 0x00      | fft_input_fifo | input data fifo                     |
+ * | 0x08      | fft_ctrl       | fft ctrl reg                        |
+ * | 0x10      | fifo_ctrl      | fifo ctrl                           |
+ * | 0x18      | intr_mask      | interrupt mask                      |
+ * | 0x20      | intr_clear     | interrupt clear                     |
+ * | 0x28      | fft_status     | fft status reg                      |
+ * | 0x30      | fft_status_raw | fft_status_raw                      |
+ * | 0x38      | fft_output_fifo| fft_output_fifo                     |
+ *
+ */
+
+
+/**
+ * @brief      input data fifo
+ *
+ *             No. 0 Register (0x00)
+ */
+typedef struct
+{
+    uint64_t fft_input_fifo : 64;
+} __attribute__((packed, aligned(8))) fft_fft_input_fifo_t;
+
+/**
+ * @brief      fft ctrl reg
+ *
+ *             No. 1 Register (0x08)
+ */
+typedef struct
+{
+    uint64_t fft_point : 3;
+    uint64_t fft_mode : 1;
+    uint64_t fft_shift : 9;
+    uint64_t fft_enable : 1;
+    uint64_t dma_send : 1;
+    uint64_t fft_input_mode : 2;
+    uint64_t fft_data_mode : 1;
+    uint64_t reserved : 46;
+} __attribute__((packed, aligned(8))) fft_fft_ctrl_t;
+
+/**
+ * @brief      fifo ctrl
+ *
+ *             No. 2 Register (0x10)
+ */
+typedef struct
+{
+    uint64_t resp_fifo_flush_n : 1;
+    uint64_t cmd_fifo_flush_n : 1;
+    uint64_t gs_fifo_flush_n : 1;
+    uint64_t reserved : 61;
+} __attribute__((packed, aligned(8))) fft_fifo_ctrl_t;
+
+/**
+ * @brief      interrupt mask
+ *
+ *             No. 3 Register (0x18)
+ */
+typedef struct
+{
+    uint64_t fft_done_mask : 1;
+    uint64_t reserved : 63;
+} __attribute__((packed, aligned(8))) fft_intr_mask_t;
+
+/**
+ * @brief      interrupt clear
+ *
+ *             No. 4 Register (0x20)
+ */
+typedef struct
+{
+    uint64_t fft_done_clear : 1;
+    uint64_t reserved1 : 63;
+} __attribute__((packed, aligned(8))) fft_intr_clear_t;
+
+/**
+ * @brief      fft status reg
+ *
+ *             No. 5 Register (0x28)
+ */
+typedef struct
+{
+    uint64_t fft_done_status : 1;
+    uint64_t reserved1 : 63;
+} __attribute__((packed, aligned(8))) fft_fft_status_t;
+
+/**
+ * @brief      fft_status_raw
+ *
+ *             No. 6 Register (0x30)
+ */
+typedef struct
+{
+    uint64_t fft_done_status_raw : 1;
+    uint64_t reserved : 63;
+} __attribute__((packed, aligned(8))) fft_fft_status_raw_t;
+
+/**
+ * @brief      fft_output_fifo
+ *
+ *             No. 7 Register (0x38)
+ */
+typedef struct
+{
+    uint64_t fft_output_fifo : 64;
+} __attribute__((packed, aligned(8))) fft_fft_output_fifo_t;
+
+/**
+ * @brief      Fast Fourier transform (FFT) algorithm accelerator object
+ *
+ *             A fast Fourier transform (FFT) algorithm computes the discrete
+ *             Fourier transform (DFT) of a sequence, or its inverse (IFFT).
+ *             Fourier analysis converts a signal from its original domain
+ *             (often time or space) to a representation in the frequency
+ *             domain and vice versa. An FFT rapidly computes such
+ *             transformations by factorizing the DFT matrix into a product of
+ *             sparse (mostly zero) factors.
+ */
+typedef struct
+{
+    /* No. 0 (0x00): input data fifo */
+    fft_fft_input_fifo_t fft_input_fifo;
+    /* No. 1 (0x08): fft ctrl reg */
+    fft_fft_ctrl_t fft_ctrl;
+    /* No. 2 (0x10): fifo ctrl */
+    fft_fifo_ctrl_t fifo_ctrl;
+    /* No. 3 (0x18): interrupt mask */
+    fft_intr_mask_t intr_mask;
+    /* No. 4 (0x20): interrupt clear */
+    fft_intr_clear_t intr_clear;
+    /* No. 5 (0x28): fft status reg */
+    fft_fft_status_t fft_status;
+    /* No. 6 (0x30): fft_status_raw */
+    fft_fft_status_raw_t fft_status_raw;
+    /* No. 7 (0x38): fft_output_fifo */
+    fft_fft_output_fifo_t fft_output_fifo;
+} __attribute__((packed, aligned(8))) fft_t;
+
+/**
+ * @brief       Fft initialize
+ *
+ * @param[in]   point           fft point, 0:512, 1:256, 2:128, 3:64
+ * @param[in]   mode            fft or ifft, 1: fft, 0: ifft
+ * @param[in]   shift           fft shift
+ * @param[in]   is_dma          dma send flag
+ * @param[in]   input_mode      fft input mode
+ * @param[in]   data_mode       fft data mode
+ *
+ * @return     Result
+ *       0     Success
+ *       Other Fail
+ */
+int fft_init(uint8_t point, uint8_t mode, uint16_t shift, uint8_t is_dma, uint8_t input_mode, uint8_t data_mode);
+
+/**
+ * @brief      Fft reset
+ *
+ */
+void fft_reset(void);
+
+/**
+ * @brief      Enable fft done interrupt
+ *
+ */
+void fft_enable_int(void);
+
+/**
+ * @brief       Fft input data(complex numbers)
+ *
+ * @param[in]   x           complex numbers real part
+ * @param[in]   y           complex numbers imaginary part
+ * @param[in]   point       fft point
+ */
+void fft_input_data(float *x, float *y, uint8_t point);
+
+/**
+ * @brief       Fft input data(integer)
+ *
+ * @param[in]   data        integer
+ * @param[in]   point       fft point
+ */
+void fft_input_intdata(int16_t *data, uint8_t point);
+
+/**
+ * @brief       Get fft finish flag
+ *
+ * @return      Result
+ *       1      Fft finish
+ *       Other  Not complete
+ */
+uint8_t fft_get_finish_flag(void);
+
+/**
+ * @brief       Get fft result
+ *
+ * @param[out]  x           complex numbers real part
+ * @param[out]  y           complex numbers imaginary part
+ * @param[in]   point        fft point
+ */
+void fft_get_result(float *x, float *y, uint8_t point);
+
+/**
+ * @brief      Fast Fourier transform (FFT) algorithm accelerator object
+ */
+extern volatile fft_t *const fft;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_FFT_H */
+

+ 434 - 0
lib/drivers/include/i2c.h

@@ -0,0 +1,434 @@
+/* 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.
+ */
+#ifndef _DRIVER_I2C_H
+#define _DRIVER_I2C_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "dmac.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define I2C_MAX_NUM 3
+
+/* clang-format off */
+struct i2c_t
+{
+    /* 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 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 struct i2c_t *const i2c[3];
+
+typedef enum
+{
+    I2C_BS_STANDARD,
+    I2C_BS_FAST,
+    I2C_BS_HIGHSPEED
+} i2c_bus_speed_mode;
+
+/**
+ * @brief       I2c init
+ *
+ * @param[in]   sel             i2c bus
+ * @param[in]   clk_pin         i2c clk pin
+ * @param[in]   data_pin        i2c data pin
+ */
+void i2c_init(uint8_t sel, int clk_pin, int data_pin);
+
+/**
+ * @brief       I2c pin init
+ *
+ * @param[in]   sel             i2c bus
+ * @param[in]   clk_pin         i2c clk pin
+ * @param[in]   data_pin        i2c data pin
+ */
+void i2c_pin_init(uint8_t sel, int clk_pin, int data_pin);
+
+/**
+ * @brief       I2c clk init
+ *
+ * @param[in]   sel     i2c bus
+ */
+void i2c_clk_init(uint8_t sel);
+
+/**
+ * @brief       I2c set param
+ *
+ * @param[in]   sel                 i2c bus
+ * @param[in]   slaveAddress        i2c slave address
+ * @param[in]   address_width       address width 7bit or 10bit
+ * @param[in]   bus_speed_mode      i2c rate
+ */
+void i2c_config(uint8_t sel, size_t slaveAddress, size_t address_width,
+                            i2c_bus_speed_mode bus_speed_mode);
+
+/**
+ * @brief       I2c send data
+ *
+ * @param[in]   sel             i2c bus
+ * @param[in]   reg             i2c slave reg address
+ * @param[in]   data_buf        send data
+ * @param[in]   length          send length
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2c_write_reg(uint8_t sel, uint8_t reg, uint8_t *data_buf, uint8_t length);
+
+ /**
+ * @brief      I2c receive data
+ *
+ * @param[in]  sel                  i2c bus
+ * @param[in]  reg                  i2c slave reg address
+ * @param[in]  data_buf             receive data
+ * @param[in]  length               receive length
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2c_read_reg(uint8_t sel, uint8_t reg, uint8_t *data_buf, uint8_t length);
+
+/**
+ * @brief       I2c send data by dma
+ *
+ * @param[in]   channel_num     dma channel
+ * @param[in]   sel             i2c bus
+ * @param[in]   reg             i2c slave reg address
+ * @param[in]   data_buf        send data
+ * @param[in]   length          send length
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2c_write_reg_dma(dmac_channel_number channel_num, uint8_t sel, uint8_t reg, uint8_t *data_buf, uint8_t length);
+
+/**
+ * @brief       I2c receive data
+ *
+ * @param[in]   channel_num     dma channel
+ * @param[in]   sel             i2c bus
+ * @param[in]   reg             i2c slave reg address
+ * @param[in]   data_buf        receive data
+ * @param[in]   length          receive length
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+*/
+int i2c_read_reg_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num,
+                        uint8_t sel, uint8_t reg, uint8_t *data_buf, uint8_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_I2C_H */

+ 1009 - 0
lib/drivers/include/i2s.h

@@ -0,0 +1,1009 @@
+/* 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.
+ */
+#ifndef _DRIVER_I2S_H
+#define _DRIVER_I2S_H
+
+#include <stdint.h>
+#include "platform.h"
+#include "io.h"
+#include "dmac.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define I2S0_IN_D0  90
+#define I2S0_SCLK   88
+#define I2S0_WS    89
+
+enum i2s_device_num_t
+{
+    I2S_DEVICE_0 = 0,
+    I2S_DEVICE_1 = 1,
+    I2S_DEVICE_2 = 2,
+    I2S_DEVICE_MAX
+};
+
+enum i2s_channel_num_t
+{
+    CHANNEL_0 = 0,
+    CHANNEL_1 = 1,
+    CHANNEL_2 = 2,
+    CHANNEL_3 = 3
+};
+
+enum i2s_transmit_t
+{
+    TRANSMITTER = 0,
+    RECEIVER = 1
+};
+
+enum i2s_work_mode_t
+{
+    STANDARD_MODE = 1,
+    RIGHT_JUSTIFYING_MODE = 2,
+    LEFT_JUSTIFYING_MODE = 4
+};
+
+enum sclk_gating_cycles_t
+{
+    /* Clock gating is diable */
+    NO_CLOCK_GATING = 0x0,
+    /* Gating after 12 sclk cycles */
+    CLOCK_CYCLES_12 = 0x1,
+    /* Gating after 16 sclk cycles */
+    CLOCK_CYCLES_16 = 0x2,
+    /* Gating after 20 sclk cycles */
+    CLOCK_CYCLES_20 = 0x3,
+    /* Gating after 24 sclk cycles */
+    CLOCK_CYCLES_24 = 0x4
+};
+
+enum word_select_cycles_t
+{
+    /* 16 sclk cycles */
+    SCLK_CYCLES_16 = 0x0,
+    /* 24 sclk cycles */
+    SCLK_CYCLES_24 = 0x1,
+    /* 32 sclk cycles */
+    SCLK_CYCLES_32 = 0x2
+
+};
+
+enum word_length_t
+{
+    /* Ignore the word length */
+    IGNORE_WORD_LENGTH = 0x0,
+    /* 12-bit data resolution of the receiver */
+    RESOLUTION_12_BIT = 0x1,
+    /* 16-bit data resolution of the receiver */
+    RESOLUTION_16_BIT = 0x2,
+    /* 20-bit data resolution of the receiver */
+    RESOLUTION_20_BIT = 0x3,
+    /* 24-bit data resolution of the receiver */
+    RESOLUTION_24_BIT = 0x4,
+    /* 32-bit data resolution of the receiver */
+    RESOLUTION_32_BIT = 0x5
+};
+
+enum fifo_threshold_t
+{
+    /* Interrupt trigger when FIFO level is 1 */
+    TRIGGER_LEVEL_1 = 0x0,
+    /* Interrupt trigger when FIFO level is 2 */
+    TRIGGER_LEVEL_2 = 0x1,
+    /* Interrupt trigger when FIFO level is 3 */
+    TRIGGER_LEVEL_3 = 0x2,
+    /* Interrupt trigger when FIFO level is 4 */
+    TRIGGER_LEVEL_4 = 0x3,
+    /* Interrupt trigger when FIFO level is 5 */
+    TRIGGER_LEVEL_5 = 0x4,
+    /* Interrupt trigger when FIFO level is 6 */
+    TRIGGER_LEVEL_6 = 0x5,
+    /* Interrupt trigger when FIFO level is 7 */
+    TRIGGER_LEVEL_7 = 0x6,
+    /* Interrupt trigger when FIFO level is 8 */
+    TRIGGER_LEVEL_8 = 0x7,
+    /* Interrupt trigger when FIFO level is 9 */
+    TRIGGER_LEVEL_9 = 0x8,
+    /* Interrupt trigger when FIFO level is 10 */
+    TRIGGER_LEVEL_10 = 0x9,
+    /* Interrupt trigger when FIFO level is 11 */
+    TRIGGER_LEVEL_11 = 0xa,
+    /* Interrupt trigger when FIFO level is 12 */
+    TRIGGER_LEVEL_12 = 0xb,
+    /* Interrupt trigger when FIFO level is 13 */
+    TRIGGER_LEVEL_13 = 0xc,
+    /* Interrupt trigger when FIFO level is 14 */
+    TRIGGER_LEVEL_14 = 0xd,
+    /* Interrupt trigger when FIFO level is 15 */
+    TRIGGER_LEVEL_15 = 0xe,
+    /* Interrupt trigger when FIFO level is 16 */
+    TRIGGER_LEVEL_16 = 0xf
+};
+
+
+struct i2s_ier_t
+{
+    /* Bit 0 is ien, 0 for disable i2s and 1 for enable i2s */
+    uint32_t ien : 1;
+    /* Bits [31:1] is reserved */
+    uint32_t resv : 31;
+} __attribute__((packed, aligned(4)));
+
+union ier_u
+{
+    struct i2s_ier_t ier;
+    uint32_t reg_data;
+};
+
+struct i2s_irer_t
+{
+    /* Bit 0 is receiver block  enable,
+     * 0 for receiver disable
+     * 1 for receiver enable
+     */
+    uint32_t rxen : 1;
+    /* Bits [31:1] is reserved */
+    uint32_t resv : 31;
+} __attribute__((packed, aligned(4)));
+
+union irer_u
+{
+    struct i2s_irer_t irer;
+    uint32_t reg_data;
+};
+
+struct i2s_iter_t
+{
+    uint32_t txen : 1;
+    /* Bit 0 is transmitter block  enable,
+     * 0 for transmitter disable
+     * 1 for transmitter enable
+     */
+    uint32_t resv : 31;
+    /* Bits [31:1] is reserved */
+} __attribute__((packed, aligned(4)));
+
+union iter_u
+{
+    struct i2s_iter_t iter;
+    uint32_t reg_data;
+};
+
+struct i2s_cer_t
+{
+    uint32_t clken : 1;
+    /* Bit 0 is clock generation enable/disable,
+     * 0 for clock generation disable,
+     * 1 for clock generation enable
+     */
+    uint32_t resv : 31;
+    /* Bits [31:1] is reserved */
+} __attribute__((packed, aligned(4)));
+
+union cer_u
+{
+    struct i2s_cer_t cer;
+    uint32_t reg_data;
+};
+
+struct i2s_ccr_t
+{
+    /* Bits [2:0] is used to program  the gating of sclk,
+     * 0x0 for clock gating is diable,
+     * 0x1 for gating after 12 sclk cycles
+     * 0x2 for gating after 16 sclk cycles
+     * 0x3 for gating after 20 sclk cycles
+     * 0x4 for gating after 24 sclk cycles
+     */
+    uint32_t clk_gate : 3;
+    /* Bits [4:3] used program  the number of sclk cycles for which the
+     * word select line stayd in the left aligned or right aligned mode.
+     * 0x0 for 16sclk cycles, 0x1 for 24 sclk cycles 0x2 for 32 sclk
+     * cycles
+     */
+    uint32_t clk_word_size : 2;
+    /* Bit[5:7] is alignment mode setting.
+     * 0x1 for standard i2s format
+     * 0x2 for right aligned format
+     * 0x4 for left aligned format
+     */
+    uint32_t align_mode : 3;
+    /* Bit[8] is DMA transmit enable control */
+    uint32_t dma_tx_en : 1;
+    /* Bit[9] is DMA receive enable control */
+    uint32_t dma_rx_en : 1;
+    uint32_t dma_divide_16 : 1;
+    /* Bit[10] split 32bit data to two 16 bit data and filled in left
+     * and right channel. Used with dma_tx_en or dma_rx_en
+     */
+    uint32_t sign_expand_en : 1;
+    uint32_t resv : 20;
+    /* Bits [31:11] is reseved */
+} __attribute__((packed, aligned(4)));
+
+union ccr_u
+{
+    struct i2s_ccr_t ccr;
+    uint32_t reg_data;
+};
+
+struct i2s_rxffr_t
+{
+    uint32_t rxffr : 1;
+    /* Bit 0 is receiver FIFO reset,
+     * 0 for does not flush RX FIFO, 1 for flush RX FIFO
+     */
+    uint32_t resv : 31;
+    /* Bits [31:1] is reserved */
+} __attribute__((packed, aligned(4)));
+
+union rxffr_u
+{
+    struct i2s_rxffr_t rxffr;
+    uint32_t reg_data;
+};
+
+struct i2s_lrbrthr
+{
+    uint32_t fifo : 16;
+    /* Bits [15:0] if used data receive or transmit */
+    uint32_t resv : 16;
+};
+
+union lrbthr_u
+{
+    struct i2s_lrbrthr buffer;
+    uint32_t reg_data;
+};
+
+struct i2s_rthr_t
+{
+    /* Bits  [15:0] is right stereo data transmitted serially
+     * from transmit channel input
+     */
+    uint32_t rthrx : 16;
+    /* Bits [31:16] is reserved */
+    uint32_t resv : 16;
+} __attribute__((packed, aligned(4)));
+
+union rthr_u
+{
+    struct i2s_rthr_t rthr;
+    uint32_t reg_data;
+};
+
+struct i2s_rer_t
+{
+    /* Bit 0 is receive channel enable/disable, 0 for receive channel disable,
+     *1 for receive channel enable
+     */
+    uint32_t rxchenx : 1;
+    /* Bits [31:1] is reseved */
+    uint32_t resv : 31;
+} __attribute__((packed, aligned(4)));
+
+union rer_u
+{
+    struct i2s_rer_t rer;
+    uint32_t reg_data;
+};
+
+struct i2s_ter_t
+{
+    /* Bit 0 is transmit channel enable/disable, 0 for transmit channel disable,
+     * 1 for transmit channel enable
+     */
+    uint32_t txchenx : 1;
+    /* Bits [31:1] is reseved */
+    uint32_t resv : 31;
+} __attribute__((packed, aligned(4)));
+
+union ter_u
+{
+    struct i2s_ter_t ter;
+    uint32_t reg_data;
+};
+
+struct i2s_rcr_tcr_t
+{
+    /* Bits [2:0] is used to program desired data resolution of
+     * receiver/transmitter,
+     * 0x0 for ignore the word length
+     * 0x1 for 12-bit data resolution of the receiver/transmitter,
+     * 0x2 for 16-bit data resolution of the receiver/transmitter,
+     * 0x3 for 20-bit data resolution of the receiver/transmitter,
+     * 0x4 for 24-bit data resolution of the receiver/transmitter,
+     * 0x5 for 32-bit data resolution of the receiver/transmitter
+     */
+    uint32_t wlen : 3;
+    /* Bits [31:3] is reseved */
+    uint32_t resv : 29;
+} __attribute__((packed, aligned(4)));
+
+union rcr_tcr_u {
+    struct i2s_rcr_tcr_t rcr_tcr;
+    uint32_t reg_data;
+};
+
+struct i2s_isr_t {
+    /* Bit 0 is status of receiver data avaliable interrupt
+     * 0x0 for RX FIFO trigger level not reached
+     * 0x1 for RX FIFO trigger level is reached
+     */
+    uint32_t rxda : 1;
+    /* Bit 1 is status of data overrun interrupt for rx channel
+     * 0x0 for RX FIFO write valid
+     * 0x1 for RX FIFO write overrun
+     */
+    uint32_t rxfo : 1;
+    /* Bits [3:2] is reserved */
+    uint32_t resv1 : 2;
+    /* Bit 4 is status of transmit empty triger interrupt
+     * 0x0 for TX FIFO triiger level is reach
+     * 0x1 for TX FIFO trigger level is not reached
+     */
+    uint32_t txfe : 1;
+    /* BIt 5 is status of data overrun interrupt for the TX channel
+     * 0x0 for TX FIFO write valid
+     * 0x1 for TX FIFO write overrun
+     */
+    uint32_t txfo : 1;
+    /* BIts [31:6] is reserved */
+    uint32_t resv2 : 26;
+} __attribute__((packed, aligned(4)));
+
+union isr_u {
+    struct i2s_isr_t isr;
+    uint32_t reg_data;
+};
+
+struct i2s_imr_t
+{
+    /* Bit 0 is mask RX FIFO data available interrupt
+     * 0x0 for unmask RX FIFO data available interrupt
+     * 0x1 for mask  RX FIFO data available interrupt
+     */
+    uint32_t rxdam : 1;
+    /* Bit 1 is mask RX FIFO overrun interrupt
+     * 0x0 for unmask RX FIFO overrun interrupt
+     * 0x1 for mask RX FIFO  overrun interrupt
+     */
+    uint32_t rxfom : 1;
+    /* Bits [3:2] is reserved */
+    uint32_t resv1 : 2;
+    /* Bit 4 is mask TX FIFO empty interrupt,
+     * 0x0 for unmask TX FIFO empty interrupt,
+     * 0x1 for mask TX FIFO empty interrupt
+     */
+    uint32_t txfem : 1;
+    /* BIt 5 is mask TX FIFO overrun interrupt
+     * 0x0 for mask TX FIFO overrun interrupt
+     * 0x1 for unmash TX FIFO overrun interrupt
+     */
+    uint32_t txfom : 1;
+    /* Bits [31:6] is reserved */
+    uint32_t resv2 : 26;
+} __attribute__((packed, aligned(4)));
+
+union imr_u
+{
+    struct i2s_imr_t imr;
+    uint32_t reg_data;
+};
+
+struct i2s_ror_t
+{
+    /* Bit 0 is read this bit to clear RX FIFO data overrun interrupt
+     * 0x0 for RX FIFO write valid,
+     *0x1 for RX FIFO write overrun
+     */
+    uint32_t rxcho : 1;
+    /* Bits [31:1] is reserved */
+    uint32_t resv : 31;
+} __attribute__((packed, aligned(4)));
+
+union ror_u
+{
+    struct i2s_ror_t ror;
+    uint32_t reg_data;
+};
+
+struct i2s_tor_t
+{
+    /* Bit 0 is read this bit to clear TX FIFO data overrun interrupt
+     * 0x0 for TX FIFO write valid,
+     *0x1 for TX FIFO write overrun
+     */
+    uint32_t txcho : 1;
+    /* Bits [31:1] is reserved */
+    uint32_t resv : 31;
+} __attribute__((packed, aligned(4)));
+
+union tor_u
+{
+    struct i2s_tor_t tor;
+    uint32_t reg_data;
+};
+
+struct i2s_rfcr_t
+{
+    /* Bits [3:0] is used program the trigger level in the RX FIFO at
+     * which the receiver data available interrupt generate,
+     * 0x0 for interrupt trigger when FIFO level is 1,
+     * 0x2 for interrupt trigger when FIFO level is 2,
+     * 0x3 for interrupt trigger when FIFO level is 4,
+     * 0x4 for interrupt trigger when FIFO level is 5,
+     * 0x5 for interrupt trigger when FIFO level is 6,
+     * 0x6 for interrupt trigger when FIFO level is 7,
+     * 0x7 for interrupt trigger when FIFO level is 8,
+     * 0x8 for interrupt trigger when FIFO level is 9,
+     * 0x9 for interrupt trigger when FIFO level is 10,
+     * 0xa for interrupt trigger when FIFO level is 11,
+     * 0xb for interrupt trigger when FIFO level is 12,
+     * 0xc for interrupt trigger when FIFO level is 13,
+     * 0xd for interrupt trigger when FIFO level is 14,
+     * 0xe for interrupt trigger when FIFO level is 15,
+     * 0xf for interrupt trigger when FIFO level is 16
+     */
+    uint32_t rxchdt : 4;
+    /* Bits [31:4] is reserved */
+    uint32_t rsvd_rfcrx : 28;
+} __attribute__((packed, aligned(4)));
+
+union rfcr_u
+{
+    struct i2s_rfcr_t rfcr;
+    uint32_t reg_data;
+};
+
+struct i2s_tfcr_t
+{
+    /* Bits [3:0] is used program the trigger level in the TX FIFO at
+     * which the receiver data available interrupt generate,
+     * 0x0 for interrupt trigger when FIFO level is 1,
+     * 0x2 for interrupt trigger when FIFO level is 2,
+     * 0x3 for interrupt trigger when FIFO level is 4,
+     * 0x4 for interrupt trigger when FIFO level is 5,
+     * 0x5 for interrupt trigger when FIFO level is 6,
+     * 0x6 for interrupt trigger when FIFO level is 7,
+     * 0x7 for interrupt trigger when FIFO level is 8,
+     * 0x8 for interrupt trigger when FIFO level is 9,
+     * 0x9 for interrupt trigger when FIFO level is 10,
+     * 0xa for interrupt trigger when FIFO level is 11,
+     * 0xb for interrupt trigger when FIFO level is 12,
+     * 0xc for interrupt trigger when FIFO level is 13,
+     * 0xd for interrupt trigger when FIFO level is 14,
+     * 0xe for interrupt trigger when FIFO level is 15,
+     * 0xf for interrupt trigger when FIFO level is 16
+     */
+    uint32_t txchet : 4;
+    /* Bits [31:4] is reserved */
+    uint32_t rsvd_tfcrx : 28;
+} __attribute__((packed, aligned(4)));
+
+union tfcr_u
+{
+    struct i2s_tfcr_t tfcr;
+    uint32_t reg_data;
+};
+
+struct i2s_rff_t
+{
+    /* Bit  0 is receiver channel FIFO reset,
+     * 0x0 for does not flush an individual RX FIFO,
+     * 0x1 for flush an indiviadual RX FIFO
+     */
+    uint32_t rxchfr : 1;
+    /*< Bits [31:1] is reserved ,write only */
+    uint32_t rsvd_rffx : 31;
+} __attribute__((packed, aligned(4)));
+
+union rff_u
+{
+    struct i2s_rff_t rff;
+    uint32_t reg_data;
+};
+
+struct i2s_tff_t
+{
+    /* Bit  0 is transmit channel FIFO reset,
+     * 0x0 for does not flush an individual TX FIFO,
+     * 0x1 for flush an indiviadual TX FIFO
+     */
+    uint32_t rtxchfr : 1;
+    /*< Bits [31:1] is reserved ,write only */
+    uint32_t rsvd_rffx : 31;
+} __attribute__((packed, aligned(4)));
+
+union tff_u
+{
+    struct i2s_tff_t tff;
+    uint32_t reg_data;
+};
+
+struct i2s_channel_t
+{
+    /* Left  Receive or Left Transmit Register      (0x20) */
+    volatile uint32_t left_rxtx;
+    /* Right Receive or Right Transmit Register     (0x24) */
+    volatile uint32_t right_rxtx;
+    /* Receive Enable Register                      (0x28) */
+    volatile uint32_t rer;
+    /* Transmit Enable Register                     (0x2c) */
+    volatile uint32_t ter;
+    /* Receive Configuration Register               (0x30) */
+    volatile uint32_t rcr;
+    /* Transmit Configuration Register              (0x34) */
+    volatile uint32_t tcr;
+    /* Interrupt Status Register                    (0x38) */
+    volatile uint32_t isr;
+    /* Interrupt Mask Register                      (0x3c) */
+    volatile uint32_t imr;
+    /* Receive Overrun Register                     (0x40) */
+    volatile uint32_t ror;
+    /* Transmit Overrun Register                    (0x44) */
+    volatile uint32_t tor;
+    /* Receive FIFO Configuration Register          (0x48) */
+    volatile uint32_t rfcr;
+    /* Transmit FIFO Configuration Register         (0x4c) */
+    volatile uint32_t tfcr;
+    /* Receive FIFO Flush Register                  (0x50) */
+    volatile uint32_t rff;
+    /* Transmit FIFO Flush Register                 (0x54) */
+    volatile uint32_t tff;
+    /* reserved                                (0x58-0x5c) */
+    volatile uint32_t reserved1[2];
+} __attribute__((packed, aligned(4)));
+
+/****is* i2s.api/dw_i2s_portmap
+ * NAME
+ *  i2s_t
+ * DESCRIPTION
+ *  This is the structure used for accessing the i2s register
+ *  portmap.
+ * EXAMPLE
+ *  struct i2s_t *portmap;
+ *  portmap = (struct dw_i2s_portmap *) DW_APB_I2S_BASE;
+ * SOURCE
+ */
+struct i2s_t
+{
+    /* I2S Enable Register                          (0x00) */
+    volatile uint32_t ier;
+    /* I2S Receiver Block Enable Register           (0x04) */
+    volatile uint32_t irer;
+    /* I2S Transmitter Block Enable Register        (0x08) */
+    volatile uint32_t iter;
+    /* Clock Enable Register                        (0x0c) */
+    volatile uint32_t cer;
+    /* Clock Configuration Register                 (0x10) */
+    volatile uint32_t ccr;
+    /* Receiver Block FIFO Reset Register           (0x04) */
+    volatile uint32_t rxffr;
+    /* Transmitter Block FIFO Reset Register        (0x18) */
+    volatile uint32_t txffr;
+    /* reserved                                     (0x1c) */
+    volatile uint32_t reserved1;
+    volatile struct i2s_channel_t channel[4];
+    /* reserved                               (0x118-0x1bc) */
+    volatile uint32_t reserved2[40];
+    /*  Receiver Block DMA Register                 (0x1c0) */
+    volatile uint32_t rxdma;
+    /* Reset Receiver Block DMA Register            (0x1c4) */
+    volatile uint32_t rrxdma;
+    /* Transmitter Block DMA Register               (0x1c8) */
+    volatile uint32_t txdma;
+    /* Reset Transmitter Block DMA Register         (0x1cc) */
+    volatile uint32_t rtxdma;
+    /* reserved                               (0x1d0-0x1ec) */
+    volatile uint32_t reserved3[8];
+    /* Component Parameter Register 2               (0x1f0) */
+    volatile uint32_t i2s_comp_param_2;
+    /* Component Parameter Register 1               (0x1f4) */
+    volatile uint32_t i2s_comp_param_1;
+    /* I2S Component Version Register               (0x1f8) */
+    volatile uint32_t i2s_comp_version_1;
+    /* I2S Component Type Register                  (0x1fc) */
+    volatile uint32_t i2s_comp_type;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief      I2S object instance
+ */
+extern volatile struct i2s_t *const i2s[3];
+
+/**
+ * @brief       i2s device
+ *
+ * @param[in]   device_num      the device of i2s
+ *
+ */
+void i2s_device_enable(enum i2s_device_num_t device_num);
+
+/**
+ * @brief       Enable or disable i2s device
+ *
+ * @param[in]   device_num      The device of i2s
+ * @param[in]   enable          Enable flag 0:disable, 1:enable
+ */
+void i2s_dev_enable(enum i2s_device_num_t device_num, uint32_t enable);
+
+/**
+ * @brief       Set I2S recive channel enable or disable
+ *
+ * @param[in]   device_num      which of device
+ * @param[in]   channel_num     The channel number
+ * @param[in]   enable          The enable or disable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_receive_channel_enable(enum i2s_device_num_t device_num,
+                   enum i2s_channel_num_t channel_num, uint32_t enable);
+
+/**
+ * @brief       Set I2S transmit channel enable or disable
+ *
+ * @param[in]   device_num      which of device
+ * @param[in]   channel_num     The channel number
+ * @param[in]   enable          The enable or disable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_transmit_channel_enable(enum i2s_device_num_t device_num,
+                enum i2s_channel_num_t channel_num, uint32_t enable);
+
+/**
+ * @brief       Read pcm data  from channel_num channel
+ *
+ * @param[in]   device_num      which of device
+ * @param[in]   channel_num     The channel number
+ * @param[in]   buf             save read data
+ * @param[in]   length          the length to read form i2s
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int32_t i2s_receive_data(enum i2s_device_num_t device_num,
+      enum i2s_channel_num_t channel_num, uint64_t *buf,
+      uint32_t length);
+
+/**
+ * @brief       Read pcm data from dma
+ *
+ * @param[in]   device_num      which of device
+ * @param[in]   buf             save read data
+ * @param[in]   length          the length to read form i2s
+ * @param[in]   channel_num     The dma channel number
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int32_t i2s_receive_data_dma(enum i2s_device_num_t device_num, uint32_t *buf,
+    uint32_t length, dmac_channel_number channel_num);
+
+/**
+ * @brief       Read pcm data from dma
+ *
+ * @param[in]   device_num      which of device
+ * @param[in]   buf             save read data
+ * @param[in]   length          the length to read form i2s
+ * @param[in]   channel_num     The dma channel number
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int32_t i2s_recv_dma(enum i2s_device_num_t device_num, uint32_t *buf,
+    uint32_t length, dmac_channel_number channel_num);
+
+/**
+ * @brief       Mask or unmask interrupt
+ *
+ * @param[in]   channel_num         The channel number
+ * @param[in]   rx_available        The receive available interrupt
+ * @param[in]   rx_overrun_int      The receive overrun interrupt
+ * @param[in]   tx_empty_int        The transmit empty interrupt
+ * @param[in]   tx_overrun_int      The transmit overrun interrupt
+ * @param[in]   device_num          which of device
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_set_mask_interrupt(enum i2s_device_num_t device_num,
+               enum i2s_channel_num_t channel_num,
+               uint32_t rx_available, uint32_t rx_overrun_int,
+               uint32_t tx_empty_int, uint32_t tx_overrun_int);
+/**
+ * @brief       Set transmit threshold
+ *
+ * @param[in]   threshold       The threshold data
+ * @param[in]   channel_num     The channel number
+ * @param[in]   device_num      which of device
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_set_tx_threshold(enum i2s_device_num_t device_num,
+             enum fifo_threshold_t threshold,
+             enum i2s_channel_num_t channel_num);
+
+/**
+ * @brief       Set receive threshold
+ *
+ * @param[in]   threshold       The threshold data
+ * @param[in]   channel_num     The channel number
+ * @param[in]   device_num      which of device
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_set_rx_threshold(enum i2s_device_num_t device_num,
+             enum fifo_threshold_t threshold,
+             enum i2s_channel_num_t channel_num);
+
+/**
+ * @brief       Configure I2s master mode word select size and clock gating param
+ *
+ * @param[in]   device_num              which of device
+ * @param[in]   word_select_size        clock cycle
+ * @param[in]   gating_cycles           The sclk gating cycles
+
+ * @param[in]   word_mode               work mode standard,left justify,
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_master_configure(enum i2s_device_num_t device_num,
+    enum word_select_cycles_t word_select_size,
+    enum sclk_gating_cycles_t gating_cycles,
+    enum i2s_work_mode_t word_mode);
+/**
+ * @brief       Set rx fifo word length
+ *
+ * @param[in]   device_num      which of device
+ * @param[in]   word_length     word length
+ * @param[in]   channel_num     The channel number
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_set_rx_word_length(enum i2s_device_num_t device_num,
+               enum word_length_t word_length,
+               enum i2s_channel_num_t channel_num);
+
+/**
+ * @brief       set tx fifo word length
+ *
+ * @param[in]   device_num      which of device
+ * @param[in]   word_length     word length
+ * @param[in]   channel_num     The channel number
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_set_tx_word_length(enum i2s_device_num_t device_num,
+               enum word_length_t word_length,
+               enum i2s_channel_num_t channel_num);
+
+/**
+ * @brief       i2s fpioa set and clock configure
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_fpioa_sysctl(void);
+
+/**
+ * @brief       i2s receive enable
+ *
+ * @param[in]   device_num      The device number
+ * @param[in]   channel_num     The channel number
+ */
+void i2s_receive_enable(enum i2s_device_num_t device_num,
+            enum i2s_channel_num_t channel_num);
+
+/**
+ * @brief       i2s transimit enable
+ *
+ * @param[in]   device_num      The device number
+ * @param[in]   channel_num     The channel number
+ */
+void i2s_transimit_enable(enum i2s_device_num_t device_num,
+              enum i2s_channel_num_t channel_num);
+
+/**
+ * @brief       I2S receive channel configure
+ *
+ * @param[in]   device_num              The device number
+ * @param[in]   channel_num             The channel number
+ * @param[in]   word_length             The word length
+ * @param[in]   word_select_size        The word select size
+ * @param[in]   trigger_level           The trigger level
+ */
+void i2s_rx_channel_configure(enum i2s_device_num_t device_num,
+    enum i2s_channel_num_t channel_num,
+    enum word_length_t word_length,
+    enum word_select_cycles_t word_select_size,
+    enum fifo_threshold_t trigger_level,
+    enum i2s_work_mode_t word_mode);
+
+/**
+ * @brief       I2S transmit channel  enable
+ *
+ * @param[in]   device_num              The device number
+ * @param[in]   channel_num             The channel number
+ * @param[in]   word_length             The word length
+ * @param[in]   word_select_size        The word select size
+ * @param[in]   trigger_level           The trigger level
+ */
+void i2s_tx_channel_configure(enum i2s_device_num_t device_num,
+    enum i2s_channel_num_t channel_num,
+    enum word_length_t word_length,
+    enum word_select_cycles_t word_select_size,
+    enum fifo_threshold_t trigger_level,
+    enum i2s_work_mode_t word_mode);
+
+/**
+ * @brief       disable block
+ *
+ * @param[in]   device_num      The device number
+ * @param[in]   rxtx_mode       The rxtx mode
+ */
+void i2s_disable_block(enum i2s_device_num_t device_num,
+    enum i2s_transmit_t rxtx_mode);
+
+/**
+ * @brief       Enable I2S transmit DMA
+ *
+ * @param[in]   device_num      The device number
+ * @param[in]   enable          The enable
+ *
+ * @return     result
+ *       0     Success
+ *       Other Fail
+ */
+int i2s_transmit_dma_enable(enum i2s_device_num_t device_num, uint32_t enable);
+
+/**
+ * @brief       Enable I2S receive DMA
+ *
+ * @param[in]   device_num      The device number
+ * @param[in]   enable          The enable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_receive_dma_enable(enum i2s_device_num_t device_num, uint32_t enable);
+
+/**
+ * @brief       Split I2S transmit DMA from 32bit to two 16bit left and right
+ *
+ * @param[in]   device_num      The device number
+ * @param[in]   enable          The enable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_transmit_dma_divide(enum i2s_device_num_t device_num, uint32_t enable);
+
+/**
+ * @brief       Write pcm data to channel_num channel
+ *
+ * @param[in]   device_num      The i2s number
+ * @param[in]   channel_num     The channel number
+ * @param[in]   pcm             32bit (16 bits left and 16bits right)pcm data
+ * @param[in]   device_num      which of device
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_transmit_data(enum i2s_device_num_t device_num,
+    enum i2s_channel_num_t channel_num, uint8_t *pcm, uint32_t length, uint8_t single_length);
+
+/**
+ * @brief       I2s init
+ *
+ * @param[in]   device_num          The device number
+ * @param[in]   rxtx_mode           I2s work mode
+ * @param[in]   channel_mask        Channel mask to which channel work
+ *
+ */
+void i2s_init(enum i2s_device_num_t device_num, enum i2s_transmit_t rxtx_mode, uint32_t channel_mask);
+
+/**
+ * @brief       Write pcm data to channel_num channel by dma
+ *
+ * @param[in]   device_num          which of device
+ * @param[in]   pcm                 Send data
+ * @param[in]   length              Send data length
+ * @param[in]   single_length       Send data width
+ * @param[in]   channel_num         dmac channel
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_transmit_data_dma(enum i2s_device_num_t device_num,
+    void *pcm, uint32_t length, uint8_t single_length, dmac_channel_number channel_num);
+
+/**
+ * @brief       Write pcm data to channel_num channel by dma, first wait dmac done
+ *
+ * @param[in]   device_num      which of device
+ * @param[in]   pcm             Send data
+ * @param[in]   length          Send data length
+ * @param[in]   channel_num     dmac channel
+ *
+ */
+void i2s_send_data_dma(enum i2s_device_num_t device_num,
+    void *pcm, uint32_t length, dmac_channel_number channel_num);
+
+/**
+ * @brief       Write pcm data to channel_num channel by dma
+ *
+ * @param[in]   device_num          which of device
+ * @param[in]   channel_num         which of device
+ * @param[in]   buf                 Send data
+ * @param[in]   length              Send data length
+ * @param[in]   frame               I2s frame number
+ * @param[in]   bits_per_sample     I2s sample bits
+ * @param[in]   track_num           track num
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int i2s_play(enum i2s_device_num_t device_num,dmac_channel_number channel_num,
+    uint8_t *buf, size_t length, uint32_t frame, uint32_t bits_per_sample, uint8_t track_num);
+
+/**
+ * @brief       Write pcm data by dma from i2s to i2s
+ *
+ * @param[in]   device_src_num      I2s receive
+ * @param[in]   device_dest_num     I2s transfer
+ * @param[in]   length              Data length
+ * @param[in]   channel_num         Dmac channel
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int32_t i2s_special_dma(enum i2s_device_num_t device_src_num, enum i2s_device_num_t device_dest_num,
+    uint32_t length, dmac_channel_number channel_num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 50 - 0
lib/drivers/include/io.h

@@ -0,0 +1,50 @@
+/* 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.
+ */
+#ifndef _DRIVER_IO_H
+#define _DRIVER_IO_H
+
+#include <stdint.h>
+
+#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 /* _DRIVER_IO_H */

+ 361 - 0
lib/drivers/include/otp.h

@@ -0,0 +1,361 @@
+/* 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.
+ */
+#ifndef _DRIVER_OTP_H
+#define _DRIVER_OTP_H
+
+#include <stdint.h>
+
+/* clang-format off */
+#define OTP_COMMON_DATA_ADDR    0x00000000U
+#define OTP_SYSTEM_DATA_ADDR    0x00003AD0U
+#define OTP_BISR_DATA_ADDR      0x00003DD0U
+#define OTP_BLOCK_CTL_ADDR      0x00003FD0U
+#define OTP_WIRED_REG_ADDR      0x00003FE0U
+#define OTP_AES_KEY_ADDR        0x00003FF0U
+
+#define OTP_BUSY_FLAG           0x00000001U
+#define OTP_BYPASS_FLAG         0x00000002U
+#define OTP_TEST_FLAG           0x00000004U
+/* clang-format on */
+
+enum otp_status_t
+{
+    OTP_OK = 0,
+    OTP_ERROR_TIMEOUT,  /* operation timeout*/
+    OTP_ERROR_ADDRESS,  /* invalid address*/
+    OTP_ERROR_WRITE,    /* write error*/
+    OTP_ERROR_BLANK,    /* blank check error*/
+    OTP_ERROR_BISR,     /* bisr error*/
+    OTP_ERROR_TESTDEC,  /* testdec error*/
+    OTP_ERROR_WRTEST,   /* wrtest error*/
+    OTP_ERROR_KEYCOMP,  /* key is wrong*/
+    OTP_ERROR_PARAM,    /* param error*/
+    OTP_ERROR_NULL,     /* undefine error*/
+    OTP_BLOCK_NORMAL,   /* block can be written*/
+    OTP_BLOCK_PROTECTED,/* block can not be written*/
+    OTP_FUNC_ENABLE,    /* function available*/
+    OTP_FUNC_DISABLE,   /* function unavailable*/
+    OTP_FLAG_SET,       /* flag set*/
+    OTP_FLAG_UNSET,     /* flag unset*/
+};
+
+enum otp_data_block_t
+{
+    COMMON_DATA_BLOCK1 = 0,
+    COMMON_DATA_BLOCK2,
+    COMMON_DATA_BLOCK3,
+    COMMON_DATA_BLOCK4,
+    COMMON_DATA_BLOCK5,
+    COMMON_DATA_BLOCK6,
+    COMMON_DATA_BLOCK7,
+    COMMON_DATA_BLOCK8,
+    COMMON_DATA_BLOCK9,
+    COMMON_DATA_BLOCK10,
+    COMMON_DATA_BLOCK11,
+    COMMON_DATA_BLOCK12,
+    COMMON_DATA_BLOCK13,
+    COMMON_DATA_BLOCK14,
+    COMMON_DATA_BLOCK15,
+    DATA_BLOCK_RESERVE,
+    SYSTEM_DATA_BLOCK1,
+    SYSTEM_DATA_BLOCK2,
+    SYSTEM_DATA_BLOCK3,
+    SYSTEM_DATA_BLOCK4,
+    SYSTEM_DATA_BLOCK5,
+    SYSTEM_DATA_BLOCK6,
+    SYSTEM_DATA_BLOCK7,
+    SYSTEM_DATA_BLOCK8,
+    SYSTEM_DATA_BLOCK9,
+    SYSTEM_DATA_BLOCK10,
+    SYSTEM_DATA_BLOCK11,
+    SYSTEM_DATA_BLOCK12,
+    SYSTEM_DATA_BLOCK13,
+    SYSTEM_DATA_BLOCK14,
+    SYSTEM_DATA_BLOCK15,
+    SYSTEM_DATA_BLOCK16,
+    SYSTEM_DATA_BLOCK17,
+    SYSTEM_DATA_BLOCK18,
+    SYSTEM_DATA_BLOCK19,
+    SYSTEM_DATA_BLOCK20,
+    SYSTEM_DATA_BLOCK21,
+    SYSTEM_DATA_BLOCK22,
+    SYSTEM_DATA_BLOCK23,
+    SYSTEM_DATA_BLOCK24,
+    SYSTEM_DATA_BLOCK25,
+    SYSTEM_DATA_BLOCK26,
+    SYSTEM_DATA_BLOCK27,
+    SYSTEM_DATA_BLOCK28,
+    SYSTEM_DATA_BLOCK29,
+    SYSTEM_DATA_BLOCK30,
+    SYSTEM_DATA_BLOCK31,
+    SYSTEM_DATA_BLOCK32,
+    SYSTEM_DATA_BLOCK33,
+    SYSTEM_DATA_BLOCK34,
+    SYSTEM_DATA_BLOCK35,
+    SYSTEM_DATA_BLOCK36,
+    SYSTEM_DATA_BLOCK37,
+    SYSTEM_DATA_BLOCK38,
+    SYSTEM_DATA_BLOCK39,
+    SYSTEM_DATA_BLOCK40,
+    SYSTEM_DATA_BLOCK41,
+    SYSTEM_DATA_BLOCK42,
+    SYSTEM_DATA_BLOCK43,
+    SYSTEM_DATA_BLOCK44,
+    SYSTEM_DATA_BLOCK45,
+    SYSTEM_DATA_BLOCK46,
+    SYSTEM_DATA_BLOCK47,
+    SYSTEM_DATA_BLOCK48,
+    DATA_BLOCK_MAX = 64,
+};
+
+enum otp_func_reg_t
+{
+    BLANK_TEST_DISABLE = 0,
+    RAM_BISR_DISABLE,
+    AES_WRITE_DISABLE,
+    AES_VERIFY_DISABLE,
+    JTAG_DISABLE,
+    TEST_EN_DISABLE = 6,
+    ISP_DISABLE,
+    OTP_FUNC_FIRMWARE_CIPHER_DISABLE,
+    FUNC_REG_MAX = 64,
+};
+
+struct otp_t
+{
+    volatile uint32_t otp_ceb;
+    volatile uint32_t otp_test_mode;
+    volatile uint32_t otp_mode;
+    volatile uint32_t gb_otp_en;
+    volatile uint32_t dat_in_finish;
+    volatile uint32_t otp_bisr_fail;
+    volatile uint32_t test_step;
+    volatile uint32_t otp_pwrrdy;
+    volatile uint32_t otp_last_dat;
+    volatile uint32_t otp_data;
+    volatile uint32_t otp_pwr_mode;
+    volatile uint32_t otp_in_dat;
+    volatile uint32_t otp_apb_adr;
+    volatile uint32_t td_result;
+    volatile uint32_t data_acp_flag;
+    volatile uint32_t otp_adr_in_flag;
+    volatile uint32_t wr_result;
+    volatile uint32_t otp_thershold;
+    volatile uint32_t bisr_finish;
+    volatile uint32_t key_cmp_result;
+    volatile uint32_t otp_cmp_key;
+    volatile uint32_t cmp_result_rdy;
+    volatile uint32_t otp_cle;
+    volatile uint32_t data_blk_ctrl;
+    volatile uint32_t otp_wrg_adr_flag;
+    volatile uint32_t pro_wrong;
+    volatile uint32_t otp_status;
+    volatile uint32_t otp_pro_adr;
+    volatile uint32_t blank_finish;
+    volatile uint32_t bisr2otp_en;
+    volatile uint32_t otp_cpu_ctrl;
+    volatile uint32_t otp_web_cpu;
+    volatile uint32_t otp_rstb_cpu;
+    volatile uint32_t otp_seltm_cpu;
+    volatile uint32_t otp_readen_cpu;
+    volatile uint32_t otp_pgmen_cpu;
+    volatile uint32_t otp_dle_cpu;
+    volatile uint32_t otp_din_cpu;
+    volatile uint32_t otp_cpumpen_cpu;
+    volatile uint32_t otp_cle_cpu;
+    volatile uint32_t otp_ceb_cpu;
+    volatile uint32_t otp_adr_cpu;
+    volatile uint32_t otp_dat_cpu;
+    volatile uint32_t otp_data_rdy;
+    volatile uint32_t block_flag_high;
+    volatile uint32_t block_flag_low;
+    volatile uint32_t reg_flag_high;
+    volatile uint32_t reg_flag_low;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Init OTP
+ *
+ * @note        The otp clock frequency is 12.5M by default
+ *
+ * @param[in]  div	bus_clk / otp_clk
+ */
+void otp_init(uint8_t div);
+
+/**
+ * @brief       Enable otp test mode
+ */
+void otp_test_enable(void);
+
+/**
+ * @brief       Disable otp test mode
+ */
+void otp_test_disable(void);
+
+/**
+ * @brief       Enable key output to aes
+ */
+void otp_key_output_enable(void);
+
+/**
+ * @brief       Disable key output to aes
+ */
+void otp_key_output_disable(void);
+
+/**
+ * @brief       Get the wrong address when programming fails
+ *
+ * @return      The wrong address
+ */
+uint32_t otp_wrong_address_get(void);
+
+/**
+ * @brief       Get OTP status
+ *
+ * @param[in]   flag        status flag
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_status_get(uint32_t flag);
+
+/**
+ * @brief       Perform the blank check operation
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_blank_check(void);
+
+/**
+ * @brief       Perform the testdec operation
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_testdec(void);
+
+/**
+ * @brief       Perform the wrtest operation
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_wrtest(void);
+
+/**
+ * @brief       Write data
+ *
+ * @param[in]   addr            Start programming address(bit)
+ * @param[in]   data_buf        Need to write the data point
+ * @param[in]   length          Need to write the data length(bit)
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_write_data(uint32_t addr, uint8_t *data_buf, uint32_t length);
+
+/**
+ * @brief       Read data
+ *
+ * @param[in]   addr            Start read address(bit).
+ * @param[in]   data_buf        Need to read the data point
+ * @param[in]   length          Need to read the data length(bit)
+ *
+ * @return     Results of the operation
+ */
+enum otp_status_t otp_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length);
+
+/**
+ * @brief       Write the key
+ *
+ * @param[in]   data_buf        The key data,length is 128 bits(4 words)
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_key_write(uint8_t *data_buf);
+
+/**
+ * @brief       Compare the key
+ *
+ * @param[in]   data_buf        The key data,length is 128 bits(4 words)
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_key_compare(uint8_t *data_buf);
+
+/**
+ * @brief       Data block write protect
+ *
+ * @param[in]   block       Need to write a protected data block
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_data_block_protect_set(enum otp_data_block_t block);
+
+/**
+ * @brief       Disable the specified function
+ *
+ * @param[in]   reg     Need to disable the function
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_func_reg_disable_set(enum otp_func_reg_t func);
+
+/**
+ * @brief       Get the data block status
+ *
+ * @param[in]   block       The specified data block
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_data_block_protect_get(enum otp_data_block_t block);
+
+/**
+ * @brief       Get the function status
+ *
+ * @param[in]   reg     The specified function
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_func_reg_disable_get(enum otp_func_reg_t func);
+
+/**
+ * @brief       Refresh the data block status
+ *
+ * @param[in]   block       The specified data block
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_data_block_protect_refresh(enum otp_data_block_t block);
+
+/**
+ * @brief       Write data(bypass mode)
+ *
+ * @param[in]   addr            Start programming address(bit)
+ * @param[in]   data_buf        Need to write the data point
+ * @param[in]   length          Need to write the data length(bit)
+ *
+ * @return     Results of the operation
+ */
+enum otp_status_t otp_soft_write(uint32_t addr, uint8_t *data_buf, uint32_t length);
+
+/**
+ * @brief       Read data(bypass mode)
+ *
+ * @param[in]   addr            Start read address(bit).Be sure to align 16 bits
+ * @param[in]   data_buf        Need to read the data point
+ * @param[in]   length          Need to read the data length(half word/16bits)
+ *
+ * @return      Results of the operation
+ */
+enum otp_status_t otp_soft_read(uint32_t addr, uint8_t *data_buf, uint32_t length);
+
+#endif

+ 462 - 0
lib/drivers/include/plic.h

@@ -0,0 +1,462 @@
+/* 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      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 hart contexts.
+ *
+ * @note       PLIC RAM Layout
+ *
+ * | Address   | Description                     |
+ * |-----------|---------------------------------|
+ * |0x0C000000 | Reserved                        |
+ * |0x0C000004 | source 1 priority               |
+ * |0x0C000008 | source 2 priority               |
+ * |...        | ...                             |
+ * |0x0C000FFC | source 1023 priority            |
+ * |           |                                 |
+ * |0x0C001000 | Start of pending array          |
+ * |...        | (read-only)                     |
+ * |0x0C00107C | End of pending array            |
+ * |0x0C001080 | Reserved                        |
+ * |...        | ...                             |
+ * |0x0C001FFF | Reserved                        |
+ * |           |                                 |
+ * |0x0C002000 | target 0 enables                |
+ * |0x0C002080 | target 1 enables                |
+ * |...        | ...                             |
+ * |0x0C1F1F80 | target 15871 enables            |
+ * |0x0C1F2000 | Reserved                        |
+ * |...        | ...                             |
+ * |0x0C1FFFFC | Reserved                        |
+ * |           |                                 |
+ * |0x0C200000 | target 0 priority threshold     |
+ * |0x0C200004 | target 0 claim/complete         |
+ * |...        | ...                             |
+ * |0x0C201000 | target 1 priority threshold     |
+ * |0x0C201004 | target 1 claim/complete         |
+ * |...        | ...                             |
+ * |0x0FFFF000 | target 15871 priority threshold |
+ * |0x0FFFF004 | target 15871 claim/complete     |
+ *
+ */
+
+#ifndef _DRIVER_PLIC_H
+#define _DRIVER_PLIC_H
+
+#include <stdint.h>
+#include "env/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_HARTS      (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_t
+{
+    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    = 33, /*!< 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.
+ */
+struct plic_source_priorities_t
+{
+    /* 0x0C000000: Reserved, 0x0C000004-0x0C000FFC: 1-1023 priorities */
+    uint32_t priority[1024];
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @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.
+ */
+struct plic_pending_bits_t {
+    /* 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)));
+
+/**
+ * @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.
+ */
+struct plic_target_enables_t
+{
+    /* 0x0C002000-0x0C1F1F80: target 0-15871 enables */
+    struct
+    {
+        uint32_t enable[32];/* Offset 0x00-0x7C: Bit 0 is zero, Bits 1-1023 is bits*/
+    } target[15872];
+    
+    /* 0x0C1F2000-0x0C1FFFFC: Reserved, size 0xE000 */
+    uint8_t resv[0xE000];
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @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.
+ */
+struct plic_target_t
+{
+    /* 0x0C200000-0x0FFFF004: target 0-15871 */
+    struct {
+        uint32_t priority_threshold;/* Offset 0x000 */
+        uint32_t claim_complete;    /* Offset 0x004 */
+        uint8_t resv[0xFF8];        /* Offset 0x008, Size 0xFF8 */
+    } target[15872];
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @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 hart contexts.
+ */
+struct plic_t
+{
+    /* 0x0C000000-0x0C000FFC */
+    struct plic_source_priorities_t source_priorities;
+    /* 0x0C001000-0x0C001FFF */
+    const struct plic_pending_bits_t pending_bits;
+    /* 0x0C002000-0x0C1FFFFC */
+    struct plic_target_enables_t target_enables;
+    /* 0x0C200000-0x0FFFF004 */
+    struct plic_target_t targets;
+} __attribute__((packed, aligned(4)));
+
+extern volatile struct plic_t *const plic;
+
+/**
+ * @brief       Definitions for the interrupt callbacks
+ */
+typedef int (*plic_irq_callback_t)(void *ctx);
+
+/**
+ * @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
+ */
+int 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
+ */
+int 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
+ */
+int plic_irq_deregister(plic_irq_t irq);
+
+/* For c++ compatibility */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_PLIC_H */

+ 603 - 0
lib/drivers/include/rtc.h

@@ -0,0 +1,603 @@
+/* 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      A real-time clock (RTC) is a computer clock that keeps track of
+ *             the current time.
+ */
+
+#ifndef _DRIVER_RTC_H
+#define _DRIVER_RTC_H
+
+#include <stdint.h>
+#include <time.h>
+#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_e;
+
+/*
+ * @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_e;
+
+/**
+ * @brief      RTC mask structure
+ *
+ *             RTC mask structure for common use
+ */
+struct rtc_mask_t {
+    /* 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)));
+
+/**
+ * @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)
+ */
+struct rtc_date_t
+{
+    /* 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)));
+
+/**
+ * @brief       Timer time information
+ *
+ *              No. 1 Register (0x04)
+ */
+struct rtc_time_t
+{
+    /* 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)));
+
+/**
+ * @brief       Alarm date information
+ *
+ *              No. 2 Register (0x08)
+ */
+struct rtc_alarm_date_t
+{
+    /* 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)));
+
+/**
+ * @brief       Alarm time information
+ *
+ *              No. 3 Register (0x0c)
+ */
+struct rtc_alarm_time_t
+{
+    /* 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)));
+
+/**
+ * @brief       Timer counter initial value
+ *
+ *              No. 4 Register (0x10)
+ */
+struct rtc_initial_count_t
+{
+    /* RTC counter initial value */
+    uint32_t count : 32;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Timer counter current value
+ *
+ *              No. 5 Register (0x14)
+ */
+struct rtc_current_count_t
+{
+    /* RTC counter current value */
+    uint32_t count : 32;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief      RTC interrupt settings
+ *
+ *             No. 6 Register (0x18)
+ */
+struct rtc_interrupt_ctrl_t
+{
+    /* 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)));
+
+/**
+ * @brief       RTC register settings
+ *
+ *              No. 7 Register (0x1c)
+ */
+struct rtc_register_ctrl_t
+{
+    /* 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 timer_mask : 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)));
+
+/**
+ * @brief       Reserved
+ *
+ *              No. 8 Register (0x20)
+ */
+struct rtc_reserved0_t
+{
+    /* Reserved */
+    uint32_t resv : 32;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief      Reserved
+ *
+ *             No. 9 Register (0x24)
+ */
+struct rtc_reserved1_t
+{
+    /* Reserved */
+    uint32_t resv : 32;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief      Timer extended information
+ *
+ *             No. 10 Register (0x28)
+ */
+struct rtc_extended_t
+{
+    /* 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)));
+
+
+/**
+ * @brief       Real-time clock struct
+ *
+ *              A real-time clock (RTC) is a computer clock that keeps track of
+ *              the current time.
+ */
+struct rtc_t
+{
+    /* No. 0 (0x00): Timer date information */
+    struct rtc_date_t date;
+    /* No. 1 (0x04): Timer time information */
+    struct rtc_time_t time;
+    /* No. 2 (0x08): Alarm date information */
+    struct rtc_alarm_date_t alarm_date;
+    /* No. 3 (0x0c): Alarm time information */
+    struct rtc_alarm_time_t alarm_time;
+    /* No. 4 (0x10): Timer counter initial value */
+    struct rtc_initial_count_t initial_count;
+    /* No. 5 (0x14): Timer counter current value */
+    struct rtc_current_count_t current_count;
+    /* No. 6 (0x18): RTC interrupt settings */
+    struct rtc_interrupt_ctrl_t interrupt_ctrl;
+    /* No. 7 (0x1c): RTC register settings */
+    struct rtc_register_ctrl_t register_ctrl;
+    /* No. 8 (0x20): Reserved */
+    struct rtc_reserved0_t reserved0;
+    /* No. 9 (0x24): Reserved */
+    struct rtc_reserved1_t reserved1;
+    /* No. 10 (0x28): Timer extended information */
+    struct rtc_extended_t extended;
+} __attribute__((packed, aligned(4)));
+
+
+/**
+ * @brief       Real-time clock object
+ */
+extern volatile struct rtc_t *const rtc;
+extern volatile uint32_t *const rtc_base;
+/**
+ * @brief       Set RTC timer mode
+ *
+ * @param[in]   timer_mode  The timer mode
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int rtc_timer_mode_set(rtc_timer_mode_e timer_mode);
+
+/**
+ * @brief       Get RTC timer mode
+ *
+ * @return      The timer mode
+ */
+rtc_timer_mode_e rtc_timer_get_mode(void);
+
+/**
+ * @brief       Set date time to RTC
+ *
+ * @param[in]   tm      The Broken-down date time
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int rtc_timer_set_tm(const struct tm *tm);
+
+/**
+ * @brief       Get date time from RTC
+ *
+ * @return      The Broken-down date time
+ */
+struct tm *rtc_timer_get_tm(void);
+
+/**
+ * @brief       Set date time to Alarm
+ *
+ * @param[in]   tm      The Broken-down date time
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int rtc_timer_set_alarm_tm(const struct tm *tm);
+
+/**
+ * @brief       Get date time from Alarm
+ *
+ * @return      The Broken-down date time
+ */
+struct tm *rtc_timer_get_alarm_tm(void);
+
+/**
+ * @brief       Check if it is a leap year
+ *
+ * @param[in]   year        The year
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int rtc_year_is_leap(int year);
+
+/**
+ * @brief       Get day of year from date
+ *
+ * @param[in]   year        The year
+ * @param[in]   month       The month
+ * @param[in]   day         The day
+ *
+ * @return      The day of year from date
+ */
+int rtc_get_yday(int year, int month, int day);
+
+/**
+ * @brief       Get the day of the week from date
+ *
+ * @param[in]   year        The year
+ * @param[in]   month       The month
+ * @param[in]   day         The day
+ *
+ * @return      The day of the week.
+ *              Where Sunday = 0, Monday = 1, Tuesday = 2, Wednesday = 3,
+ *              Thursday = 4, Friday = 5, Saturday = 6.
+ */
+int rtc_get_wday(int year, int month, int day);
+
+/**
+ * @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      Set date time to Alarm
+ *
+ * @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_alarm(int year, int month, int day, int hour, int minute, int second);
+
+/**
+ * @brief       Get date time from Alarm
+ *
+ * @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_alarm(int *year, int *month, int *day, int *hour, int *minute, int *second);
+
+/**
+ * @brief       Set rtc tick interrupt
+ *
+ * @param       enable       enable or disale rtc interrupt
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int rtc_tick_interrupt_set(int enable);
+
+/**
+ * @brief       Get tick interrupt
+ *
+ *
+ * @return      Result
+ *     - 0      Disable
+ *     - 1      Enable
+ */
+int rtc_tick_interrupt_get(void);
+
+/**
+ * @brief       Set tick interrupt mode
+ *
+ * @param       mode        The mode interrumpted
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int rtc_tick_interrupt_mode_set(rtc_tick_interrupt_mode_e mode);
+
+/**
+ * @brief       Get tick interrupt mode
+ *
+ * @return      Tick interrupt mode
+ */
+rtc_tick_interrupt_mode_e rtc_tick_interrupt_mode_get(void);
+
+/**
+ * @brief       Enable alarm interrupt
+ *
+ * @param       enable      Enable or disable alarm interrupt
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int rtc_alarm_interrupt_set(int enable);
+
+/**
+ * @brief       Get alarm interrupt status
+ *
+ * @return      Alarm interrupt status
+ */
+int rtc_alarm_interrupt_get(void);
+
+/**
+ * @brief       Set alarm interrupt mask
+ *
+ * @param       mask        Alarm interrupt mask
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int rtc_alarm_interrupt_mask_set(struct rtc_mask_t mask);
+
+/**
+ * @brief       Get alarm interrupt mask
+ *
+ * @return      Alarm interrupt mask
+ */
+struct rtc_mask_t rtc_alarm_interrupt_mask_get(void);
+
+/**
+ * @brief       Initialize RTC
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int rtc_init(void);
+
+/**
+ * @brief       RTC timer set mode
+ *
+ * @param       timer_mode      timer mode
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int rtc_timer_set_mode(rtc_timer_mode_e timer_mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_RTC_H */

+ 94 - 0
lib/drivers/include/sha256.h

@@ -0,0 +1,94 @@
+/* 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.
+ */
+#ifndef _SHA256_H
+#define _SHA256_H
+
+#include <stdint.h>
+#include "env/encoding.h"
+#include "platform.h"
+
+#define DISABLE_SHA_DMA 0
+#define ENABLE_SHA_DMA  1
+
+/**
+ * @brief       AES
+ *
+ */
+struct sha256_t
+{
+    uint32_t sha_result[8];
+    uint32_t sha_data_in1;
+    uint32_t sha_data_in2;
+    uint32_t sha_data_num; /*1 unit represents 64 bytes*/
+    uint32_t sha_status;
+    uint32_t reserved0;
+    uint32_t sha_input_ctrl;
+} __attribute__((packed, aligned(4)));
+
+#define SHA256_HASH_SIZE 32
+
+/* Hash size in 32-bit words */
+#define SHA256_HASH_WORDS 8
+
+struct _SHA256Context
+{
+    uint64_t totalLength;
+    uint32_t hash[SHA256_HASH_WORDS];
+    uint32_t bufferLength;
+    union
+    {
+        uint32_t words[16];
+        uint8_t bytes[64];
+    } buffer;
+#ifdef RUNTIME_ENDIAN
+    int littleEndian;
+#endif /* RUNTIME_ENDIAN */
+};
+
+typedef struct _SHA256Context SHA256Context;
+
+/**
+ * @brief       Sha256 initialize
+ *
+ * @param[in]   dma_en          Dma enable flag
+ * @param[in]   input_size      Input size
+ * @param[in]   sc              Sha256 Context point
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sha256_init(uint8_t dma_en, uint32_t input_size, SHA256Context *sc);
+
+/**
+ * @brief       Sha256 update
+ *
+ * @param[in]   sc          Sha256 Context point
+ * @param[in]   data        Input data point
+ * @param[in]   len         Input data size
+ *
+ */
+void sha256_update(SHA256Context *sc, const void *data, uint32_t len);
+
+/**
+ * @brief       Sha256 final
+ *
+ * @param[in]   sc          Sha256 Context point
+ * @param[out]  hash        Sha256 result
+ *
+ */
+void sha256_final(SHA256Context *sc, uint8_t hash[SHA256_HASH_SIZE]);
+
+#endif

+ 449 - 0
lib/drivers/include/spi.h

@@ -0,0 +1,449 @@
+/* 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.
+ */
+#ifndef _DRIVER_SPI_H
+#define _DRIVER_SPI_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "dmac.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clang-format off */
+struct spi_t {
+    /* 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)));
+/* clang-format on */
+
+
+typedef enum
+{
+    SPI_MODE_0,
+    SPI_MODE_1,
+    SPI_MODE_2,
+    SPI_MODE_3,
+} spi_mode;
+
+typedef enum
+{
+    SPI_FF_STANDARD,
+    SPI_FF_DUAL,
+    SPI_FF_QUAD,
+    SPI_FF_OCTAL
+} spi_frame_format;
+
+typedef enum
+{
+    SPI_AITM_STANDARD,
+    SPI_AITM_ADDR_STANDARD,
+    SPI_AITM_AS_FRAME_FORMAT
+} spi_addr_inst_trans_mode;
+
+typedef enum
+{
+    SPI_TMOD_TRANS_RECV,
+    SPI_TMOD_TRANS,
+    SPI_TMOD_RECV,
+    SPI_TMOD_EEROM
+}spi_transfer_mode;
+
+
+typedef enum _spi_transfer_width
+{
+    SPI_TRANS_CHAR  = 0x0,
+    SPI_TRANS_SHORT = 0x1,
+    SPI_TRANS_INT   = 0x2,
+}spi_transfer_width;
+
+
+extern volatile struct spi_t *const spi[4];
+
+
+/**
+ * @brief       Spi initialize
+ *
+ * @param[in]   spi_bus     Spi bus number
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int spi_init(uint8_t spi_bus);
+
+/**
+ * @brief       Spi master mode configuration
+ *
+ * @param[in]   spi_bus             Spi bus number
+ * @param[in]   mode                Spi mode
+ * @param[in]   frame_format        Spi frame format
+ * @param[in]   data_bit_length     Spi data bit length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int spi_master_config(uint8_t spi_bus, spi_mode mode, spi_frame_format frame_format,
+                           size_t data_bit_length);
+
+/**
+ * @brief       Spi transmit configuration
+ *
+ * @param[in]   spi_bus                 Spi bus number
+ * @param[in]   instruction_length      Instruction length
+ * @param[in]   address_length          Address length
+ * @param[in]   wait_cycles             Wait cycles
+ * @param[in]   trans_mode              Spi transfer mode
+ *
+ */
+void spi_trans_config(uint8_t spi_bus, size_t instruction_length, size_t address_length,
+                           size_t wait_cycles, spi_addr_inst_trans_mode trans_mode);
+
+/**
+ * @brief       Spi send data
+ *
+ * @param[in]   spi_bus         Spi bus number
+ * @param[in]   chip_sel        Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         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
+ */
+int spi_send_data(uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff,
+                      uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len);
+
+
+/**
+ * @brief       Spi receive data
+ *
+ * @param[in]   spi_bus             Spi bus number
+ * @param[in]   chip_sel            Spi chip select
+ * @param[in]   cmd_buff            Spi command buffer point
+ * @param[in]   cmd_len             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
+ */
+int spi_receive_data(uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff,
+                         uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len);
+
+
+/**
+ * @brief       Spi special receive data
+ *
+ * @param[in]   spi_bus         Spi bus number
+ * @param[in]   chip_sel        Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         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
+ */
+int spi_special_receive_data(uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff,
+                                    uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len);
+
+/**
+ * @brief       Spi special send data
+ *
+ * @param[in]   spi_bus         Spi bus number
+ * @param[in]   chip_sel        Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         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
+ */
+int spi_special_send_data(uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff,
+                                uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len);
+
+/**
+ * @brief       Spi set transfer mode
+ *
+ * @param[in]   spi_bus     Spi bus number
+ * @param[in]   tmod        Spi tmod
+ *
+ */
+void spi_set_tmod(uint8_t spi_bus, uint32_t tmod);
+
+/**
+ * @brief       Spi set frame format
+ *
+ * @param[in]   spi_bus     Spi bus number
+ * @param[in]   spi_frf     Spi frame format
+ *
+ */
+void spi_set_frame_format(uint8_t spi_bus, uint32_t spi_frf);
+
+/**
+ * @brief       Spi get frame format
+ *
+ * @param[in]   spi_bus     Spi bus number
+ *
+ * @return      frame foramt
+ */
+int spi_get_frame_format(uint8_t spi_bus);
+
+/**
+ * @brief       Spi set work mode
+ *
+ * @param[in]   spi_bus     Spi bus number
+ * @param[in]   mode        Spi work mode
+ *
+ */
+void spi_set_work_mode(uint8_t spi_bus, spi_mode mode);
+
+/**
+ * @brief       Spi set frame size
+ *
+ * @param[in]   spi_bus     Spi bus number
+ * @param[in]   dfs         Spi frame size
+ *
+ */
+void spi_set_frame_size(uint8_t spi_bus, uint32_t dfs);
+
+/**
+ * @brief       Spi set wait cycles
+ *
+ * @param[in]   spi_bus     Spi bus number
+ * @param[in]   wcycles     Spi wait cycles
+ *
+ */
+void spi_set_wait_cycles(uint8_t spi_bus, uint32_t wcycles);
+
+/**
+ * @brief       Spi set instruction length
+ *
+ * @param[in]   spi_bus                 Spi bus number
+ * @param[in]   instruction_length      Spi instruction length
+ *
+ */
+void spi_set_inst_length(uint8_t spi_bus, uint32_t instruction_length);
+
+/**
+ * @brief       Spi set address length
+ *
+ * @param[in]   spi_bus             Spi bus number
+ * @param[in]   address_length      Spi address length
+ *
+ */
+void spi_set_address_length(uint8_t spi_bus, uint32_t address_length);
+
+/**
+ * @brief       Spi set transfer mode
+ *
+ * @param[in]   spi_bus         Spi bus number
+ * @param[in]   trans_mode      Spi tansfer mode
+ *
+ */
+void spi_set_trans_mode(uint8_t spi_bus, spi_addr_inst_trans_mode trans_mode);
+
+/**
+ * @brief       Spi send data by dma
+ *
+ * @param[in]   channel_num     Dmac channel number
+ * @param[in]   spi_bus         Spi bus number
+ * @param[in]   chip_sel        Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         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
+ */
+int spi_send_data_dma(dmac_channel_number channel_num, uint8_t spi_bus, uint32_t chip_sel,
+                           uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_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_bus             Spi bus number
+ * @param[in]   chip_sel            Spi chip select
+ * @param[in]   cmd_buff            Spi command buffer point
+ * @param[in]   cmd_len             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
+ */
+int spi_receive_data_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num,
+                               uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len);
+
+
+/**
+ * @brief       Spi special send data by dma
+ *
+ * @param[in]   channel_num     Dmac channel number
+ * @param[in]   spi_bus         Spi bus number
+ * @param[in]   chip_sel        Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         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
+ */
+int spi_special_send_data_dma(dmac_channel_number channel_num,uint8_t spi_bus, uint32_t chip_sel,
+                                     uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len);
+
+/**
+ * @brief       Spi special 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_bus             Spi bus number
+ * @param[in]   chip_sel            Spi chip select
+ * @param[in]   cmd_buff            Spi command buffer point
+ * @param[in]   cmd_len             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
+ */
+int spi_special_receive_data_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num,
+                                         uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len);
+
+/**
+ * @brief       Spi fill dma
+ *
+ * @param[in]   channel_num     Dmac channel number
+ * @param[in]   spi_bus         Spi bus number
+ * @param[in]   chip_sel        Spi chip select
+ * @param[in]   cmd_buff        Spi command buffer point
+ * @param[in]   cmd_len         Spi command length
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int spi_fill_dma(dmac_channel_number channel_num,uint8_t spi_bus, uint32_t chip_sel,
+                    uint32_t *cmd_buff, uint32_t cmd_len);
+
+/**
+ * @brief       Spi normal send by dma
+ *
+ * @param[in]   channel_num     Dmac channel number
+ * @param[in]   spi_bus         Spi bus number
+ * @param[in]   chip_sel        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
+ */
+int spi_normal_send_dma(dmac_channel_number channel_num, uint8_t spi_bus, uint32_t chip_sel,
+                             void *tx_buff, uint32_t tx_len, spi_transfer_width stw);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_SPI_H */

+ 43 - 0
lib/drivers/include/sysclock.h

@@ -0,0 +1,43 @@
+/* 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.
+ */
+#ifndef _SYS_CLOCK_H
+#define _SYS_CLOCK_H
+#include "stdint.h"
+
+#define PLL0_OUTPUT_FREQ 320000000UL
+#define PLL1_OUTPUT_FREQ 160000000UL
+#define PLL2_OUTPUT_FREQ 45158400UL
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief       Init PLL freqency
+ */
+void sys_clock_init();
+
+/**
+ * @brief       Set frequency of CPU
+ * @param[in]   frequency       The desired frequency in Hz
+ *
+ * @return      The actual frequency of CPU after set
+ */
+uint32_t system_set_cpu_frequency(uint32_t frequency);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 1016 - 0
lib/drivers/include/sysctl.h

@@ -0,0 +1,1016 @@
+/* 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.
+ */
+#ifndef _DRIVER_SYSCTL_H
+#define _DRIVER_SYSCTL_H
+
+#include <stdint.h>
+#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                            |
+ *
+ */
+
+enum sysctl_pll_e
+{
+    SYSCTL_PLL0,
+    SYSCTL_PLL1,
+    SYSCTL_PLL2,
+    SYSCTL_PLL_MAX
+};
+
+enum sysctl_clock_source_e
+{
+    SYSCTL_SOURCE_IN0,
+    SYSCTL_SOURCE_PLL0,
+    SYSCTL_SOURCE_PLL1,
+    SYSCTL_SOURCE_PLL2,
+    SYSCTL_SOURCE_ACLK,
+    SYSCTL_SOURCE_MAX
+};
+
+enum sysctl_dma_channel_e
+{
+    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
+};
+
+enum sysctl_dma_select_e
+{
+    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
+};
+
+/**
+ * @brief      System controller clock id
+ */
+enum sysctl_clock_e
+{
+    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_MAX
+};
+
+/**
+ * @brief      System controller clock select id
+ */
+enum sysctl_clock_select_e
+{
+    SYSCTL_CLOCK_SELECT_PLL0_BYPASS,
+    SYSCTL_CLOCK_SELECT_PLL1_BYPASS,
+    SYSCTL_CLOCK_SELECT_PLL3_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
+};
+
+/**
+ * @brief      System controller clock threshold id
+ */
+enum sysctl_threshold_e
+{
+    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
+};
+
+/**
+ * @brief      System controller reset control id
+ */
+enum sysctl_reset_e
+{
+    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
+};
+
+/**
+ * @brief       Git short commit id
+ *
+ *              No. 0 Register (0x00)
+ */
+struct sysctl_git_id_t
+{
+    uint32_t git_id : 32;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       System clock base frequency
+ *
+ *              No. 1 Register (0x04)
+ */
+struct sysctl_clk_freq_t
+{
+    uint32_t clk_freq : 32;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       PLL0 controller
+ *
+ *              No. 2 Register (0x08)
+ */
+struct sysctl_pll0_t
+{
+    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)));
+
+/**
+ * @brief       PLL1 controller
+ *
+ *              No. 3 Register (0x0c)
+ */
+struct sysctl_pll1_t
+{
+    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)));
+
+/**
+ * @brief       PLL2 controller
+ *
+ *              No. 4 Register (0x10)
+ */
+struct sysctl_pll2_t
+{
+    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)));
+
+/**
+ * @brief       PLL lock tester
+ *
+ *              No. 6 Register (0x18)
+ */
+struct sysctl_pll_lock_t
+{
+    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)));
+
+/**
+ * @brief       AXI ROM detector
+ *
+ *              No. 7 Register (0x1c)
+ */
+struct sysctl_rom_error_t
+{
+    uint32_t rom_mul_error : 1;
+    uint32_t rom_one_error : 1;
+    uint32_t reserved : 30;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Clock select controller0
+ *
+ *              No. 8 Register (0x20)
+ */
+struct sysctl_clk_sel0_t
+{
+    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)));
+
+/**
+ * @brief       Clock select controller1
+ *
+ *              No. 9 Register (0x24)
+ */
+struct sysctl_clk_sel1_t
+{
+    uint32_t spi3_sample_clk_sel : 1;
+    uint32_t reserved0 : 30;
+    uint32_t reserved1 : 1;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Central clock enable
+ *
+ *              No. 10 Register (0x28)
+ */
+struct sysctl_clk_en_cent_t
+{
+    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)));
+
+/**
+ * @brief       Peripheral clock enable
+ *
+ *              No. 11 Register (0x2c)
+ */
+struct sysctl_clk_en_peri_t
+{
+    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)));
+
+/**
+ * @brief       Soft reset ctrl
+ *
+ *              No. 12 Register (0x30)
+ */
+struct sysctl_soft_reset_t
+{
+    uint32_t soft_reset : 1;
+    uint32_t reserved : 31;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Peripheral reset controller
+ *
+ *              No. 13 Register (0x34)
+ */
+struct sysctl_peri_reset_t
+{
+    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)));
+
+/**
+ * @brief       Clock threshold controller 0
+ *
+ *              No. 14 Register (0x38)
+ */
+struct sysctl_clk_th0_t
+{
+    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)));
+
+/**
+ * @brief       Clock threshold controller 1
+ *
+ *              No. 15 Register (0x3c)
+ */
+struct sysctl_clk_th1_t
+{
+    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)));
+
+/**
+ * @brief       Clock threshold controller 2
+ *
+ *              No. 16 Register (0x40)
+ */
+struct sysctl_clk_th2_t
+{
+    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)));
+
+/**
+ * @brief       Clock threshold controller 3
+ *
+ *              No. 17 Register (0x44)
+ */
+struct sysctl_clk_th3_t
+{
+    uint32_t i2s0_clk_threshold : 16;
+    uint32_t i2s1_clk_threshold : 16;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Clock threshold controller 4
+ *
+ *              No. 18 Register (0x48)
+ */
+struct sysctl_clk_th4_t
+{
+    uint32_t i2s2_clk_threshold : 16;
+    uint32_t i2s0_mclk_threshold : 8;
+    uint32_t i2s1_mclk_threshold : 8;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Clock threshold controller 5
+ *
+ *              No. 19 Register (0x4c)
+ */
+struct sysctl_clk_th5_t
+{
+    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)));
+
+/**
+ * @brief       Clock threshold controller 6
+ *
+ *              No. 20 Register (0x50)
+ */
+struct sysctl_clk_th6_t
+{
+    uint32_t wdt0_clk_threshold : 8;
+    uint32_t wdt1_clk_threshold : 8;
+    uint32_t reserved0 : 8;
+    uint32_t reserved1 : 8;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Miscellaneous controller
+ *
+ *              No. 21 Register (0x54)
+ */
+struct sysctl_misc_t
+{
+    uint32_t debug_sel : 6;
+    uint32_t reserved0 : 5;
+    uint32_t reserved1 : 21;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       Peripheral controller
+ *
+ *              No. 22 Register (0x58)
+ */
+struct sysctl_peri_t
+{
+    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)));
+
+/**
+ * @brief       SPI sleep controller
+ *
+ *              No. 23 Register (0x5c)
+ */
+struct sysctl_spi_sleep_t
+{
+    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)));
+
+/**
+ * @brief       Reset source status
+ *
+ *              No. 24 Register (0x60)
+ */
+struct sysctl_reset_status_t
+{
+    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)));
+
+/**
+ * @brief       DMA handshake selector
+ *
+ *              No. 25 Register (0x64)
+ */
+struct sysctl_dma_sel0_t
+{
+    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)));
+
+/**
+ * @brief       DMA handshake selector
+ *
+ *              No. 26 Register (0x68)
+ */
+struct sysctl_dma_sel1_t
+{
+    uint32_t dma_sel5 : 6;
+    uint32_t reserved : 26;
+} __attribute__((packed, aligned(4)));
+
+/**
+ * @brief       IO Power Mode Select controller
+ *
+ *              No. 27 Register (0x6c)
+ */
+struct sysctl_power_sel_t
+{
+    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)));
+
+
+/**
+ * @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.
+ */
+struct sysctl_t
+{
+    /* No. 0 (0x00): Git short commit id */
+    struct sysctl_git_id_t git_id;
+    /* No. 1 (0x04): System clock base frequency */
+    struct sysctl_clk_freq_t clk_freq;
+    /* No. 2 (0x08): PLL0 controller */
+    struct sysctl_pll0_t pll0;
+    /* No. 3 (0x0c): PLL1 controller */
+    struct sysctl_pll1_t pll1;
+    /* No. 4 (0x10): PLL2 controller */
+    struct sysctl_pll2_t pll2;
+    /* No. 5 (0x14): Reserved */
+    uint32_t resv5;
+    /* No. 6 (0x18): PLL lock tester */
+    struct sysctl_pll_lock_t pll_lock;
+    /* No. 7 (0x1c): AXI ROM detector */
+    struct sysctl_rom_error_t rom_error;
+    /* No. 8 (0x20): Clock select controller0 */
+    struct sysctl_clk_sel0_t clk_sel0;
+    /* No. 9 (0x24): Clock select controller1 */
+    struct sysctl_clk_sel1_t clk_sel1;
+    /* No. 10 (0x28): Central clock enable */
+    struct sysctl_clk_en_cent_t clk_en_cent;
+    /* No. 11 (0x2c): Peripheral clock enable */
+    struct sysctl_clk_en_peri_t clk_en_peri;
+    /* No. 12 (0x30): Soft reset ctrl */
+    struct sysctl_soft_reset_t soft_reset;
+    /* No. 13 (0x34): Peripheral reset controller */
+    struct sysctl_peri_reset_t peri_reset;
+    /* No. 14 (0x38): Clock threshold controller 0 */
+    struct sysctl_clk_th0_t clk_th0;
+    /* No. 15 (0x3c): Clock threshold controller 1 */
+    struct sysctl_clk_th1_t clk_th1;
+    /* No. 16 (0x40): Clock threshold controller 2 */
+    struct sysctl_clk_th2_t clk_th2;
+    /* No. 17 (0x44): Clock threshold controller 3 */
+    struct sysctl_clk_th3_t clk_th3;
+    /* No. 18 (0x48): Clock threshold controller 4 */
+    struct sysctl_clk_th4_t clk_th4;
+    /* No. 19 (0x4c): Clock threshold controller 5 */
+    struct sysctl_clk_th5_t clk_th5;
+    /* No. 20 (0x50): Clock threshold controller 6 */
+    struct sysctl_clk_th6_t clk_th6;
+    /* No. 21 (0x54): Miscellaneous controller */
+    struct sysctl_misc_t misc;
+    /* No. 22 (0x58): Peripheral controller */
+    struct sysctl_peri_t peri;
+    /* No. 23 (0x5c): SPI sleep controller */
+    struct sysctl_spi_sleep_t spi_sleep;
+    /* No. 24 (0x60): Reset source status */
+    struct sysctl_reset_status_t reset_status;
+    /* No. 25 (0x64): DMA handshake selector */
+    struct sysctl_dma_sel0_t dma_sel0;
+    /* No. 26 (0x68): DMA handshake selector */
+    struct sysctl_dma_sel1_t dma_sel1;
+    /* No. 27 (0x6c): IO Power Mode Select controller */
+    struct 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)));
+
+/**
+ * @brief       System controller object instanse
+ */
+extern volatile struct 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(enum sysctl_clock_e clock);
+
+/**
+ * @brief       Enable clock for peripheral
+ *
+ * @param[in]   clock       The clock to be disable
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sysctl_clock_disable(enum sysctl_clock_e 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(enum sysctl_threshold_e 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(enum sysctl_threshold_e 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(enum sysctl_clock_select_e 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(enum sysctl_clock_select_e which);
+
+/**
+ * @brief       Get clock source frequency
+ *
+ * @param[in]   input       The input clock source
+ *
+ * @return      The frequency of clock source
+ */
+uint32_t sysctl_clock_source_get_freq(enum sysctl_clock_source_e input);
+
+/**
+ * @brief       Get PLL frequency
+ *
+ * @param[in]   pll     The PLL id
+ *
+ * @return      The frequency of PLL
+ */
+uint32_t sysctl_pll_get_freq(enum sysctl_pll_e pll);
+
+/**
+ * @brief       Set PLL frequency and input clock
+ *
+ * @param[in]   pll     The PLL id
+ * @param[in]   sel     The selected PLL input clock
+ * @param[in]   freq    The frequency
+ *
+ * @return      The frequency of PLL
+ */
+uint32_t sysctl_pll_set_freq(enum sysctl_pll_e pll, enum sysctl_clock_source_e source, uint32_t freq);
+
+/**
+ * @brief       Get base clock frequency by clock id
+ *
+ * @param[in]   clock       The clock id
+ *
+ * @return      The clock frequency
+ */
+uint32_t sysctl_clock_get_freq(enum sysctl_clock_e clock);
+
+/**
+ * @brief       Reset device by reset controller
+ *
+ * @param[in]   reset       The reset signal
+ */
+void sysctl_reset(enum sysctl_reset_e reset);
+
+/**
+ * @brief       Get git commit id
+ *
+ * @return      The 4 bytes git commit id
+ */
+uint32_t sysctl_get_git_id(void);
+
+/**
+ * @brief       Get base clock frequency, default is 26MHz
+ *
+ * @return      The base clock frequency
+ */
+uint32_t sysctl_get_freq(void);
+
+/**
+ * @brief       Get pll lock status
+ *
+ * @param[in]   pll     The pll id
+ *
+ * @return      The lock status
+ *     - 1      Pll is lock
+ *     - 0      Pll have lost lock
+ */
+int sysctl_pll_is_lock(enum sysctl_pll_e pll);
+
+/**
+ * @brief       Clear pll lock status
+ *
+ * @param[in]   pll     The pll id
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sysctl_pll_clear_slip(enum sysctl_pll_e pll);
+
+/**
+ * @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(enum sysctl_pll_e pll);
+
+/**
+ * @brief       Disable the PLL and power off
+ *
+ * @param[in]   pll     The pll id
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int sysctl_pll_disable(enum sysctl_pll_e 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(enum sysctl_dma_channel_e channel, enum sysctl_dma_select_e select);
+
+/**
+ * @brief       Fast set all PLL and CPU clock
+ *
+ * @return      Result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+uint32_t sysctl_pll_fast_enable_pll(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_SYSCTL_H */

+ 290 - 0
lib/drivers/include/timer.h

@@ -0,0 +1,290 @@
+/* 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.
+ */
+#ifndef _DRIVER_TIMER_H
+#define _DRIVER_TIMER_H
+
+#include <stdint.h>
+#include <stddef.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clang-format off */
+struct timer_channel_t
+{
+    /* 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)));
+
+struct timer_t
+{
+    /* TIMER_N Register                         (0x00-0x4c) */
+    volatile struct 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)));
+
+/* 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 struct timer_t *const timer[3];
+
+/**
+ * @brief       Set timer clock frequency
+ *
+ * @param[in]   timer       timer
+ * @param[in]   div         clock divide value
+ */
+void timer_set_clock_div(uint32_t timer, uint32_t div);
+
+/**
+ * @brief       Enable timer channel
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ */
+void timer_enable(uint32_t timer, uint32_t channel);
+
+/**
+ * @brief       Disable timer channel
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ */
+void timer_disable(uint32_t timer, uint32_t channel);
+
+/**
+ * @brief       Enable timer channel PWM
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ */
+void timer_enable_pwm(uint32_t timer, uint32_t channel);
+
+/**
+ * @brief       Disable timer channel PWM
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ */
+void timer_disable_pwm(uint32_t timer, uint32_t channel);
+
+/**
+ * @brief       Enable timer channel interrupt
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ */
+void timer_enable_interrupt(uint32_t timer, uint32_t channel);
+
+/**
+ * @brief       Disable timer channel interrupt
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ */
+void timer_disable_interrupt(uint32_t timer, uint32_t channel);
+
+/**
+ * @brief       Set timer channel mode
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ * @param[in]   mode        mode
+ */
+void timer_set_mode(uint32_t timer, uint32_t channel, uint32_t mode);
+
+/**
+ * @brief       Set timer channel reload value
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ * @param[in]   count       count
+ */
+void timer_set_reload(uint32_t timer, uint32_t channel, uint32_t count);
+
+/**
+ * @brief       Set timer channel reload value2
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ * @param[in]   count       count
+ */
+void timer_set_reload2(uint32_t timer, uint32_t channel, uint32_t count);
+
+/**
+ * @brief       Get timer channel count
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ *
+ * @return      current value
+ */
+uint32_t timer_get_count(uint32_t timer, uint32_t channel);
+
+/**
+ * @brief       Get timer channel reload value
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ *
+ * @return      reload value
+ */
+uint32_t timer_get_reload(uint32_t timer, uint32_t channel);
+
+/**
+ * @brief       Get timer channel reload value2
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ *
+ * @return      reload value2
+ */
+uint32_t timer_get_reload2(uint32_t timer, uint32_t channel);
+
+/**
+ * @brief       Get timer interrupt status
+ *
+ * @param[in]   timer       timer
+ *
+ * @return      interrupt status
+ */
+uint32_t timer_get_interrupt_status(uint32_t timer);
+
+/**
+ * @brief       Get timer raw interrupt status
+ *
+ * @param[in]   timer    timer
+ *
+ * @return      raw interrupt status
+ */
+uint32_t timer_get_raw_interrupt_status(uint32_t timer);
+
+/**
+ * @brief       Get timer interrupt status
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ *
+ * @return      interrupt status
+ */
+uint32_t timer_channel_get_interrupt_status(uint32_t timer, uint32_t channel);
+
+/**
+ * @brief       Clear interrupt
+ *
+ * @param[in]   timer       timer
+ */
+void timer_clear_interrupt(uint32_t timer);
+
+/**
+ * @brief       Clear interrupt
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ */
+void timer_channel_clear_interrupt(uint32_t timer, uint32_t channel);
+
+
+/**
+ * @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(uint32_t timer, uint32_t channel, size_t nanoseconds);
+
+/**
+ * @brief       Init timer
+ *
+ * @param[in]   timer       timer
+ */
+void timer_init(uint32_t timer);
+
+/**
+ * @brief       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(uint32_t timer, uint32_t channel, void(*func)(),  uint32_t priority);
+
+/**
+ * @brief       Enable timer
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ * @param[in]   enable      Enable or disable
+ *
+ */
+void timer_set_enable(uint32_t timer, uint32_t channel, uint32_t enable);
+
+/**
+ * @brief       Enable timer
+ *
+ * @param[in]   timer       timer
+ * @param[in]   channel     channel
+ * @param[in]   enable      Enable or disable
+ *
+ */
+void pwm_set_enable(uint32_t timer, uint32_t channel, int enable);
+
+/**
+ * @brief       Set pwm duty
+ *
+ * @param[in]   timer           timer
+ * @param[in]   channel         channel
+ * @param[in]   frequency       pwm frequency
+ * @param[in]   duty            duty
+ *
+ */
+double pwm_set_frequency(uint32_t timer, uint32_t channel, double frequency, double duty);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_TIMER_H */

+ 209 - 0
lib/drivers/include/uart.h

@@ -0,0 +1,209 @@
+/* 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.
+ *
+ *
+ */
+
+#ifndef _DRIVER_APBUART_H
+#define _DRIVER_APBUART_H
+
+#include <stdint.h>
+#include "platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum
+{
+    UART_DEV1 = 0,
+    UART_DEV2,
+    UART_DEV3,
+} uart_dev_t;
+
+typedef struct
+{
+    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 reserve[18];
+    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 R[5];
+    volatile uint32_t CPR;
+    volatile uint32_t UCV;
+    volatile uint32_t CTR;
+} uart_t;
+
+typedef enum
+{
+    UART_BITWIDTH_5BIT = 0,
+    UART_BITWIDTH_6BIT,
+    UART_BITWIDTH_7BIT,
+    UART_BITWIDTH_8BIT,
+} uart_bitwidth_t;
+
+typedef enum
+{
+    UART_STOPBIT_1 = 0,
+    UART_STOPBIT_1P5OR2,
+} uart_stopbit_t;
+
+typedef enum
+{
+    UART_PORITY_DISABLE = 0,
+    UART_PORITY_ODD     = 1,
+    UART_PORITY_EVEN    = 3
+} uart_pority_t;
+
+typedef struct
+{
+    uint32_t baudrate;
+    uart_bitwidth_t bitwidth;
+    uart_stopbit_t stopbit;
+    uart_pority_t pority;
+    uint32_t is_hw_flow_en;
+} uart_info_t;
+
+typedef enum
+{
+    DISABLE = 0,
+    ENABLE,
+} uart_rede_sel;
+
+typedef enum
+{
+    UART_STOP_1,
+    UART_STOP_1_5,
+    UART_STOP_2
+} uart_stopbit;
+
+typedef enum
+{
+    UART_PARITY_None,
+    UART_PARITY_Odd,
+    UART_PARITY_Even
+} uart_parity;
+
+/**
+ * @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 uart_write(uint8_t channel, const char* buffer, size_t len);
+
+/**
+ * @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 uart_read(uint8_t channel, char* buffer, size_t len);
+
+/**
+ * @brief       Init uart
+ *
+ * @param[in]   channel     Uart index
+ *
+ */
+void uartapb_init(uint8_t channel);
+
+/**
+ * @brief       Set uart param
+ *
+ * @param[in]   channel         Uart index
+ * @param[in]   baud_rate       Baudrate
+ * @param[in]   data_width      Data width
+ * @param[in]   stopbit         Stop bit
+ * @param[in]   parity          Odd Even parity
+ *
+ */
+void uart_config(uint8_t channel, size_t baud_rate, size_t data_width, uart_stopbit stopbit, uart_parity parity);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_APBUART_H */

+ 223 - 0
lib/drivers/include/uarths.h

@@ -0,0 +1,223 @@
+/* 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               |
+ *
+ */
+
+#ifndef _DRIVER_UARTHS_H
+#define _DRIVER_UARTHS_H
+
+#include <stdint.h>
+#include "platform.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 */
+
+struct uarths_txdata_t
+{
+    /* 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)));
+
+struct uarths_rxdata_t
+{
+    /* 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)));
+
+struct uarths_txctrl_t
+{
+    /* 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)));
+
+struct uarths_rxctrl_t
+{
+    /* 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)));
+
+struct uarths_ip_t
+{
+    /* 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)));
+
+struct uarths_ie_t
+{
+    /* 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)));
+
+struct uarths_div_t
+{
+    /* 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)));
+
+struct uarths_t
+{
+    /* Address offset 0x00 */
+    struct uarths_txdata_t txdata;
+    /* Address offset 0x04 */
+    struct uarths_rxdata_t rxdata;
+    /* Address offset 0x08 */
+    struct uarths_txctrl_t txctrl;
+    /* Address offset 0x0c */
+    struct uarths_rxctrl_t rxctrl;
+    /* Address offset 0x10 */
+    struct uarths_ie_t ie;
+    /* Address offset 0x14 */
+    struct uarths_ip_t ip;
+    /* Address offset 0x18 */
+    struct uarths_div_t div;
+} __attribute__((packed, aligned(4)));
+
+extern volatile struct uarths_t *const uarths;
+
+/**
+ * @brief       Initialization Core UART
+ *
+ * @return      result
+ *     - 0      Success
+ *     - Other  Fail
+ */
+int uart_init();
+
+/**
+ * @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 uart_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 uart_puts(const char *s);
+
+
+/**
+ * @brief       Get a byte from UART
+ *
+ * @return      byte as int type from UART
+ */
+int uart_getc(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_UARTHS_H */

+ 189 - 0
lib/drivers/include/wdt.h

@@ -0,0 +1,189 @@
+/* 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.
+ */
+#ifndef _DRIVER_WDT_H
+#define _DRIVER_WDT_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <plic.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clang-format off */
+struct wdt_t
+{
+    /* 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)));
+
+
+#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       WDT object instanse
+ */
+extern volatile struct wdt_t *const wdt[2];
+
+/**
+ * @brief       Feed wdt
+ */
+void wdt_feed(uint8_t id);
+
+/**
+ * @brief       Enable wdt
+ *
+ * @param[in]   id      Wdt id 0 or 1
+ *
+ */
+void wdt_enable(uint8_t id);
+
+/**
+ * @brief       Clear wdt interrupt
+ *
+ * @param[in]   id      Wdt id 0 or 1
+ *
+ */
+void wdt_interrupt_clear(uint8_t id);
+
+/**
+ * @brief       Clear wdt interrupt
+ *
+ * @param[in]   id      Wdt id 0 or 1
+ * @param[in]   mode    Set wdt work mode
+ *
+ */
+void wdt_response_mode(uint8_t id, uint8_t mode);
+
+/**
+ * @brief       Set wdt timeout
+ *
+ * @param[in]   id          Wdt id 0 or 1
+ * @param[in]   timeout     Wdt trigger time
+ *
+ */
+void wdt_timeout_set(uint8_t id, uint8_t timeout);
+
+/**
+ * @brief       Start wdt
+ *
+ * @param[in]   id          Wdt id 0 or 1
+ * @param[in]   toms        Wdt trigger time
+ *
+ */
+int wdt_start(uint8_t id, size_t toms);
+
+/**
+ * @brief       Stop wdt
+ *
+ * @param[in]   id      Wdt id 0 or 1
+ *
+ */
+void wdt_stop(uint8_t id);
+
+/**
+ * @brief       Set wdt interrupt function
+ *
+ * @param[in]   id          Wdt id 0 or 1
+ * @param[in]   on_irq      Wdt interrupt function
+ *
+ */
+void wdt_set_irq(uint8_t id, plic_irq_callback_t on_irq);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_WDT_H */

+ 602 - 0
lib/drivers/otp.c

@@ -0,0 +1,602 @@
+/* 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.
+ */
+#include "otp.h"
+#include "platform.h"
+#include "sysctl.h"
+
+/* clang-format off */
+#define DELAY_TIMEOUT       0xFFFFFFU
+#define WRTEST_NUM          0xA5U
+/* clang-format on */
+
+volatile struct otp_t* const otp = (volatile struct otp_t*)OTP_BASE_ADDR;
+
+void otp_init(uint8_t div)
+{
+    sysctl_clock_enable(SYSCTL_CLOCK_OTP);
+    otp->otp_cpu_ctrl = 0;
+    otp->otp_thershold = div;
+    otp->data_blk_ctrl = 0;
+    otp->gb_otp_en = 0;
+    otp->otp_pwr_mode = 0;
+    otp->otp_web_cpu = 1;
+    otp->otp_rstb_cpu = 1;
+    otp->otp_seltm_cpu = 0;
+    otp->otp_readen_cpu = 0;
+    otp->otp_pgmen_cpu = 0;
+    otp->otp_dle_cpu = 0;
+    otp->otp_din_cpu = 0;
+    otp->otp_cpumpen_cpu = 0;
+    otp->otp_cle_cpu = 0;
+    otp->otp_ceb_cpu = 1;
+    otp->otp_adr_cpu = 0;
+    otp->otp_dat_cpu = 0;
+}
+
+void otp_test_enable(void)
+{
+    otp->otp_cpu_ctrl = 0xCAAC;
+}
+
+void otp_test_disable(void)
+{
+    otp->otp_cpu_ctrl = 0;
+}
+
+void otp_key_output_enable(void)
+{
+    otp->gb_otp_en = 1;
+}
+
+void otp_key_output_disable(void)
+{
+    otp->gb_otp_en = 0;
+}
+
+enum otp_status_t otp_status_get(uint32_t flag)
+{
+    if (otp->otp_status & flag)
+        return OTP_FLAG_SET;
+    return OTP_FLAG_UNSET;
+}
+
+static enum otp_status_t otp_bisr_write(void)
+{
+    uint32_t time_out = 0;
+
+    otp->otp_cle = 1;
+    otp->otp_mode = 0x02;
+    otp->otp_test_mode = 0x30;
+    otp->test_step = 0;
+    otp->otp_ceb = 0;
+    while (otp->bisr_finish == 0)
+    {
+        time_out++;
+        if (time_out >= DELAY_TIMEOUT)
+            return OTP_ERROR_TIMEOUT;
+    }
+    otp->bisr_finish = 0;
+    if (otp->pro_wrong)
+        return OTP_ERROR_BISR;
+    return OTP_OK;
+}
+
+static enum otp_status_t otp_bisr_read(void)
+{
+    uint32_t time_out = 0;
+
+    otp->otp_cle = 1;
+    otp->otp_mode = 0x02;
+    otp->otp_test_mode = 0x30;
+    otp->test_step = 1;
+    otp->otp_ceb = 0;
+    while (otp->bisr_finish == 0)
+    {
+        time_out++;
+        if (time_out >= DELAY_TIMEOUT)
+            return OTP_ERROR_TIMEOUT;
+    }
+    otp->bisr_finish = 0;
+    return OTP_OK;
+}
+
+enum otp_status_t otp_blank_check(void)
+{
+    enum otp_status_t status;
+    uint32_t time_out = 0;
+
+    if (otp_func_reg_disable_get(BLANK_TEST_DISABLE) == OTP_FUNC_DISABLE)
+        return OTP_FUNC_DISABLE;
+
+    otp->otp_cle = 1;
+    otp->otp_mode = 0x02;
+    otp->otp_test_mode = 0x24;
+    otp->blank_finish = 0;
+    otp->otp_ceb = 0;
+    while (otp->blank_finish == 0)
+    {
+        time_out++;
+        if (time_out >= DELAY_TIMEOUT)
+            return OTP_ERROR_TIMEOUT;
+    }
+    if (otp->otp_bisr_fail)
+        return OTP_ERROR_BLANK;
+
+    status = otp_bisr_write();
+    if (status != OTP_OK)
+        return status;
+    status = otp_bisr_read();
+    if (status != OTP_OK)
+        return status;
+    status = otp_func_reg_disable_set(BLANK_TEST_DISABLE);
+    if (status != OTP_OK)
+        return status;
+    return OTP_OK;
+}
+
+enum otp_status_t otp_testdec(void)
+{
+    uint32_t time_out = 0;
+
+    otp->otp_cle = 1;
+    otp->otp_mode = 0x02;
+    otp->otp_test_mode = 0x21;
+    otp->otp_ceb = 0;
+    while (otp->td_result == 0)
+    {
+        time_out++;
+        if (time_out >= DELAY_TIMEOUT)
+            return OTP_ERROR_TIMEOUT;
+    }
+    if (otp->td_result == 0x01)
+    {
+        otp->td_result = 0;
+        return OTP_ERROR_TESTDEC;
+    }
+    return OTP_OK;
+}
+
+enum otp_status_t otp_wrtest(void)
+{
+    uint16_t addr, data, i, j;
+    uint32_t time_out;
+
+    otp->otp_cle = 1;
+    otp->otp_mode = 0x02;
+    otp->otp_test_mode = 0x01;
+    otp->test_step = 0;
+    otp->data_acp_flag = 0;
+    otp->otp_ceb = 0;
+    addr = 0;
+    for (i = 0; i < 128; i++)
+    {
+        data = WRTEST_NUM;
+        for (j = 0; j < 8; j++)
+        {
+            if ((addr == 1023) || (data & 0x01))
+            {
+                time_out = 0;
+                while (otp->otp_adr_in_flag == 0)
+                {
+                    time_out++;
+                    if (time_out >= DELAY_TIMEOUT)
+                        return OTP_ERROR_TIMEOUT;
+                }
+                otp->otp_apb_adr = addr;
+                if (addr == 1023)
+                {
+                    otp->otp_in_dat = data & 0x01;
+                    otp->otp_last_dat = 0x01;
+                }
+                else
+                    otp->otp_in_dat = 0x01;
+                otp->dat_in_finish = 0x01;
+                time_out = 0;
+                while (otp->data_acp_flag == 0)
+                {
+                    time_out++;
+                    if (time_out >= DELAY_TIMEOUT)
+                        return OTP_ERROR_TIMEOUT;
+                }
+                if (otp->data_acp_flag == 0x01)
+                {
+                    otp->data_acp_flag = 0;
+                    return OTP_ERROR_WRITE;
+                }
+                otp->data_acp_flag = 0;
+            }
+            data >>= 1;
+            addr++;
+        }
+    }
+    time_out = 0;
+    while ((otp->wr_result & 0x04) == 0)
+    {
+        time_out++;
+        if (time_out >= DELAY_TIMEOUT)
+            return OTP_ERROR_TIMEOUT;
+    }
+    otp->wr_result &= 0xFFFFFFFB;
+
+    otp->otp_cle = 1;
+    otp->otp_mode = 0x02;
+    otp->otp_test_mode = 0x01;
+    otp->test_step = 1;
+    otp->data_acp_flag = 0;
+    otp->otp_ceb = 0;
+    addr = 0;
+    for (i = 0; i < 128; i++)
+    {
+        time_out = 0;
+        while (otp->otp_adr_in_flag == 0)
+        {
+            time_out++;
+            if (time_out >= DELAY_TIMEOUT)
+                return OTP_ERROR_TIMEOUT;
+            if (otp->wr_result == 0x01)
+            {
+                otp->wr_result = 0;
+                return OTP_ERROR_WRTEST;
+            }
+        }
+        otp->otp_in_dat = WRTEST_NUM;
+        otp->otp_apb_adr = addr;
+        if (i == 127)
+            otp->otp_last_dat = 0x01;
+        addr += 8;
+    }
+    time_out = 0;
+    while ((otp->wr_result & 0x03) == 0)
+    {
+        time_out++;
+        if (time_out >= DELAY_TIMEOUT)
+            return OTP_ERROR_TIMEOUT;
+    }
+    if ((otp->wr_result & 0x03) == 0x01)
+    {
+        otp->wr_result = 0;
+        return OTP_ERROR_WRTEST;
+    }
+    return OTP_OK;
+}
+
+static enum otp_status_t otp_write_byte(uint32_t addr, uint8_t* data_buf, uint32_t length)
+{
+    enum otp_status_t status;
+    uint8_t data, index;
+    uint32_t time_out;
+
+    otp->otp_cle = 0;
+    otp->otp_mode = 1;
+    otp->data_acp_flag = 0;
+    otp->otp_wrg_adr_flag = 0;
+    otp->otp_ceb = 0;
+    index = 0;
+    addr *= 8;
+    length *= 8;
+    data = *data_buf++;
+    while (length--)
+    {
+        if ((length == 0) || (data & 0x01))
+        {
+            time_out = 0;
+            while (otp->otp_adr_in_flag == 0)
+            {
+                time_out++;
+                if (time_out >= DELAY_TIMEOUT)
+                    return OTP_ERROR_TIMEOUT;
+            }
+            otp->otp_apb_adr = addr;
+            if (length == 0)
+            {
+                otp->otp_in_dat = data & 0x01;
+                otp->otp_last_dat = 1;
+            }
+            else
+                otp->otp_in_dat = 1;
+            otp->dat_in_finish = 1;
+            time_out = 0;
+            while (otp->data_acp_flag == 0)
+            {
+                time_out++;
+                if (time_out >= DELAY_TIMEOUT)
+                    return OTP_ERROR_TIMEOUT;
+            }
+            if (otp->otp_wrg_adr_flag == 1)
+                return OTP_ERROR_ADDRESS;
+            if (otp->data_acp_flag == 1)
+                return OTP_ERROR_WRITE;
+            otp->data_acp_flag = 0;
+        }
+        data >>= 1;
+        addr++;
+        index++;
+        if (index == 8)
+        {
+            index = 0;
+            data = *data_buf++;
+        }
+    }
+
+    status = otp_bisr_write();
+    if (status != OTP_OK)
+        return status;
+    status = otp_bisr_read();
+    if (status != OTP_OK)
+        return status;
+    return OTP_OK;
+}
+
+static enum otp_status_t otp_read_byte(uint32_t addr, uint8_t* data_buf, uint32_t length)
+{
+    uint32_t time_out;
+
+    otp->otp_cle = 0;
+    otp->otp_mode = 0;
+    otp->otp_wrg_adr_flag = 0;
+    otp->otp_ceb = 0;
+    addr *= 8;
+    while (length--)
+    {
+        time_out = 0;
+        while (otp->otp_adr_in_flag == 0)
+        {
+            time_out++;
+            if (time_out >= DELAY_TIMEOUT)
+                return OTP_ERROR_TIMEOUT;
+        }
+        if (length == 0)
+            otp->otp_last_dat = 1;
+        otp->otp_apb_adr = addr;
+        time_out = 0;
+        while (otp->otp_data_rdy == 0)
+        {
+            time_out++;
+            if (time_out >= DELAY_TIMEOUT)
+                return OTP_ERROR_TIMEOUT;
+        }
+        if (otp->otp_wrg_adr_flag == 0x01)
+            return OTP_ERROR_ADDRESS;
+        *data_buf++ = otp->otp_data;
+        addr += 8;
+    }
+    return OTP_OK;
+}
+
+enum otp_status_t otp_write_data(uint32_t addr, uint8_t* data_buf, uint32_t length)
+{
+    enum otp_status_t status;
+
+    if (addr >= OTP_BISR_DATA_ADDR)
+        return OTP_ERROR_ADDRESS;
+    length = length <= OTP_BISR_DATA_ADDR - addr ? length : OTP_BISR_DATA_ADDR - addr;
+
+    status = otp_write_byte(addr, data_buf, length);
+    if (status == OTP_ERROR_ADDRESS)
+        status = OTP_BLOCK_PROTECTED;
+    return status;
+}
+
+enum otp_status_t otp_read_data(uint32_t addr, uint8_t* data_buf, uint32_t length)
+{
+    enum otp_status_t status;
+
+    if (addr >= OTP_BISR_DATA_ADDR)
+        return OTP_ERROR_ADDRESS;
+    length = length <= OTP_BISR_DATA_ADDR - addr ? length : OTP_BISR_DATA_ADDR - addr;
+
+    status = otp_read_byte(addr, data_buf, length);
+    if (status == OTP_ERROR_ADDRESS)
+        status = OTP_ERROR_NULL;
+    return status;
+}
+
+enum otp_status_t otp_key_write(uint8_t* data_buf)
+{
+    enum otp_status_t status;
+
+    status = otp_write_byte(OTP_AES_KEY_ADDR, data_buf, 16);
+    if (status == OTP_ERROR_ADDRESS)
+        status = OTP_FUNC_DISABLE;
+    return status;
+}
+
+enum otp_status_t otp_key_compare(uint8_t* data_buf)
+{
+    uint32_t time_out = 0;
+
+    otp->key_cmp_result = 0;
+    otp->otp_cmp_key = ((uint32_t)data_buf[0] << 24) | ((uint32_t)data_buf[1] << 16) | ((uint32_t)data_buf[2] << 8) | (uint32_t)data_buf[3];
+    otp->otp_cmp_key = ((uint32_t)data_buf[4] << 24) | ((uint32_t)data_buf[5] << 16) | ((uint32_t)data_buf[6] << 8) | (uint32_t)data_buf[7];
+    otp->otp_cmp_key = ((uint32_t)data_buf[8] << 24) | ((uint32_t)data_buf[9] << 16) | ((uint32_t)data_buf[10] << 8) | (uint32_t)data_buf[11];
+    otp->otp_cmp_key = ((uint32_t)data_buf[12] << 24) | ((uint32_t)data_buf[13] << 16) | ((uint32_t)data_buf[14] << 8) | (uint32_t)data_buf[15];
+    while (otp->key_cmp_result == 0)
+    {
+        time_out++;
+        if (time_out >= DELAY_TIMEOUT)
+            return OTP_ERROR_TIMEOUT;
+    }
+    if (otp->key_cmp_result == 0x01)
+        return OTP_ERROR_KEYCOMP;
+    else if (otp->key_cmp_result == 0x03)
+        return OTP_FUNC_DISABLE;
+    return OTP_OK;
+}
+
+enum otp_status_t otp_data_block_protect_set(enum otp_data_block_t block)
+{
+    enum otp_status_t status;
+    uint8_t value;
+
+    if (block >= DATA_BLOCK_MAX)
+        return OTP_ERROR_PARAM;
+    otp->data_blk_ctrl = 0x01;
+    value = 0x03 << ((block % 4) * 2);
+    status = otp_write_byte(OTP_BLOCK_CTL_ADDR + block / 4, &value, 1);
+    otp->data_blk_ctrl = 0;
+    return status;
+}
+
+enum otp_status_t otp_func_reg_disable_set(enum otp_func_reg_t func)
+{
+    enum otp_status_t status;
+    uint8_t value;
+
+    if (func >= FUNC_REG_MAX)
+        return OTP_ERROR_PARAM;
+    otp->data_blk_ctrl = 0x01;
+    value = 0x03 << ((func % 4) * 2);
+    status = otp_write_byte(OTP_WIRED_REG_ADDR + func / 4, &value, 1);
+    otp->data_blk_ctrl = 0;
+    return status;
+}
+
+enum otp_status_t otp_data_block_protect_get(enum otp_data_block_t block)
+{
+    if (block < DATA_BLOCK_MAX / 2)
+    {
+        if (otp->block_flag_low & (0x01 << block))
+            return OTP_BLOCK_PROTECTED;
+    }
+    else if (block < DATA_BLOCK_MAX)
+    {
+        if (otp->block_flag_high & (0x01 << (block - DATA_BLOCK_MAX / 2)))
+            return OTP_BLOCK_PROTECTED;
+    }
+    else
+        return OTP_ERROR_PARAM;
+    return OTP_BLOCK_NORMAL;
+}
+
+enum otp_status_t otp_func_reg_disable_get(enum otp_func_reg_t func)
+{
+    if (func < FUNC_REG_MAX / 2)
+    {
+        if (otp->reg_flag_low & (0x01 << func))
+            return OTP_FUNC_DISABLE;
+    }
+    else if (func < FUNC_REG_MAX)
+    {
+        if (otp->reg_flag_high & (0x01 << (func - FUNC_REG_MAX / 2)))
+            return OTP_FUNC_DISABLE;
+    }
+    else
+        return OTP_ERROR_PARAM;
+    return OTP_FUNC_ENABLE;
+}
+
+enum otp_status_t otp_data_block_protect_refresh(enum otp_data_block_t block)
+{
+    uint8_t value;
+
+    if (block < DATA_BLOCK_MAX)
+        return otp_read_byte(OTP_BLOCK_CTL_ADDR + block / 4, &value, 1);
+    else
+        return OTP_ERROR_PARAM;
+}
+
+enum otp_status_t otp_soft_write(uint32_t addr, uint8_t* data_buf, uint32_t length)
+{
+    uint8_t data, index, count;
+
+    otp->otp_ceb_cpu = 1;
+    otp->otp_cle_cpu = 0;
+    otp->otp_seltm_cpu = 0;
+    otp->otp_readen_cpu = 0;
+    otp->otp_dle_cpu = 0;
+    otp->otp_web_cpu = 1;
+    otp->otp_cpumpen_cpu = 0;
+    otp->otp_pgmen_cpu = 0;
+    otp->otp_rstb_cpu = 1;
+
+    otp->otp_ceb_cpu = 0;
+    otp->otp_rstb_cpu = 0;
+    otp->otp_rstb_cpu = 1;
+
+    index = 0;
+    addr *= 8;
+    length *= 8;
+    data = *data_buf++;
+    while (length)
+    {
+        otp->otp_adr_cpu = addr;
+        otp->otp_din_cpu = data & 0x01;
+        otp->otp_dle_cpu = 1;
+        otp->otp_web_cpu = 0;
+        otp->otp_web_cpu = 1;
+        otp->otp_dle_cpu = 0;
+        count = 20;
+        while (count--)
+        {
+            otp->otp_pgmen_cpu = 1;
+            otp->otp_cpumpen_cpu = 1;
+            otp->otp_web_cpu = 0;
+            otp->otp_web_cpu = 1;
+            otp->otp_cpumpen_cpu = 0;
+            otp->otp_pgmen_cpu = 0;
+            if (otp->otp_dat_cpu == 0)
+                break;
+        }
+        if (otp->otp_dat_cpu & 0x01)
+            break;
+        data >>= 1;
+        addr++;
+        index++;
+        if (index == 8)
+        {
+            index = 0;
+            data = *data_buf++;
+        }
+        length--;
+    }
+    otp->otp_ceb_cpu = 1;
+    if (length)
+        return OTP_ERROR_WRITE;
+    return OTP_OK;
+}
+
+enum otp_status_t otp_soft_read(uint32_t addr, uint8_t* data_buf, uint32_t length)
+{
+    otp->otp_ceb_cpu = 1;
+    otp->otp_dle_cpu = 0;
+    otp->otp_cle_cpu = 0;
+    otp->otp_pgmen_cpu = 0;
+    otp->otp_web_cpu = 1;
+    otp->otp_readen_cpu = 0;
+    otp->otp_rstb_cpu = 1;
+
+    otp->otp_ceb_cpu = 0;
+    otp->otp_rstb_cpu = 0;
+    otp->otp_rstb_cpu = 1;
+
+    while (length)
+    {
+        otp->otp_adr_cpu = addr;
+        otp->otp_readen_cpu = 1;
+        *data_buf++ = otp->otp_dat_cpu;
+        otp->otp_readen_cpu = 0;
+        addr += 8;
+        length--;
+    }
+    otp->otp_ceb_cpu = 1;
+    if (length)
+        return OTP_ERROR_WRITE;
+    return OTP_OK;
+}
+
+uint32_t otp_wrong_address_get(void)
+{
+    return otp->otp_pro_adr;
+}

+ 204 - 0
lib/drivers/plic.c

@@ -0,0 +1,204 @@
+/* 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.
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include "env/encoding.h"
+#include "plic.h"
+#include "syscalls.h"
+#include "syslog.h"
+
+volatile struct plic_t* const plic = (volatile struct plic_t*)PLIC_BASE_ADDR;
+
+struct plic_instance_t
+{
+    plic_irq_callback_t callback;
+    void* ctx;
+};
+
+static struct plic_instance_t plic_instance[PLIC_NUM_HARTS][IRQN_MAX];
+
+int plic_init(void)
+{
+    int i = 0;
+
+    /* Get current hart id */
+    unsigned long hart_id = read_csr(mhartid);
+
+    /* Disable all interrupts for the current hart. */
+    for (i = 0; i < ((PLIC_NUM_SOURCES + 32u) / 32u); i++)
+        plic->target_enables.target[hart_id].enable[i] = 0;
+
+    /* Set priorities to zero. */
+    for (i = 0; i < PLIC_NUM_SOURCES; i++)
+        plic->source_priorities.priority[i] = 0;
+
+    /* Set the threshold to zero. */
+    plic->targets.target[hart_id].priority_threshold = 0;
+
+    /* Clear PLIC instance for every cores */
+    for (i = 0; i < IRQN_MAX; i++)
+    {
+        /* clang-format off */
+        plic_instance[hart_id][i] = (const struct 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[hart_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);
+    return 0;
+}
+
+int plic_irq_enable(plic_irq_t irq_number)
+{
+    /* Check parameters */
+    if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
+        return -1;
+    unsigned long hart_id = read_csr(mhartid);
+    /* Get current enable bit array by IRQ number */
+    uint32_t current = plic->target_enables.target[hart_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[hart_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 hart_id = read_csr(mhartid);
+    /* Get current enable bit array by IRQ number */
+    uint32_t current = plic->target_enables.target[hart_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[hart_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 hart_id = read_csr(mhartid);
+    /* Perform IRQ claim */
+    return plic->targets.target[hart_id].claim_complete;
+}
+
+int plic_irq_complete(uint32_t source)
+{
+    unsigned long hart_id = read_csr(mhartid);
+    /* Perform IRQ complete */
+    plic->targets.target[hart_id].claim_complete = source;
+    return 0;
+}
+
+int plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void* ctx)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* Set user callback function */
+    plic_instance[hart_id][irq].callback = callback;
+    /* Assign user context */
+    plic_instance[hart_id][irq].ctx = ctx;
+    return 0;
+}
+
+int plic_irq_deregister(plic_irq_t irq)
+{
+    /* Just assign NULL to user callback function and context */
+    return plic_irq_register(irq, NULL, NULL);
+}
+
+/*Entry Point for PLIC Interrupt Handler*/
+uintptr_t handle_irq_m_ext(uintptr_t cause, uintptr_t epc, uintptr_t regs[32])
+{
+    /*
+     * 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 hart id */
+        uint64_t hart_id = read_csr(mhartid);
+        /* Get primitive interrupt enable flag */
+        uint64_t ie_flag = read_csr(mie);
+        /* Get current IRQ num */
+        uint32_t int_num = plic->targets.target[hart_id].claim_complete;
+        /* Get primitive IRQ threshold */
+        uint32_t int_threshold = plic->targets.target[hart_id].priority_threshold;
+        /* Set new IRQ threshold = current IRQ threshold */
+        plic->targets.target[hart_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[hart_id][int_num].callback)
+            plic_instance[hart_id][int_num].callback(
+                plic_instance[hart_id][int_num].ctx);
+        /* Perform IRQ complete */
+        plic->targets.target[hart_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[hart_id].priority_threshold = int_threshold;
+    }
+
+    return epc;
+}

+ 581 - 0
lib/drivers/rtc.c

@@ -0,0 +1,581 @@
+/* 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.
+ */
+#include <stdint.h>
+#include <time.h>
+#include <stdlib.h>
+#include "env/encoding.h"
+#include "sysctl.h"
+#include "rtc.h"
+
+volatile struct rtc_t *const rtc = (volatile struct rtc_t *)RTC_BASE_ADDR;
+
+struct tm rtc_date_time;
+
+int rtc_timer_set_mode(rtc_timer_mode_e timer_mode)
+{
+    struct 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;
+
+    return 0;
+}
+
+rtc_timer_mode_e rtc_timer_get_mode(void)
+{
+    struct rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
+    rtc_timer_mode_e 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_RUNNING;
+    }
+    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)
+{
+    struct rtc_date_t timer_date;
+    struct rtc_time_t timer_time;
+    struct 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 = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU);
+        /* Set threshold to 1/26000000 s */
+        freq = freq / 26000000;
+        /* Get current CPU cycle */
+        unsigned long start_cycle = read_csr(mcycle);
+        /* Wait for 1/26000000 s to sync data */
+        while (read_csr(mcycle) - 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)
+{
+    struct rtc_alarm_date_t alarm_date;
+    struct 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;
+}
+
+int rtc_year_is_leap(int year)
+{
+    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
+}
+
+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;
+}
+
+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;
+
+    struct rtc_date_t timer_date = rtc->date;
+    struct rtc_time_t timer_time = rtc->time;
+    struct 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 % 31;
+    tm->tm_mon = (timer_date.month % 12) - 1;
+    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;
+
+    struct rtc_alarm_date_t alarm_date = rtc->alarm_date;
+    struct rtc_alarm_time_t alarm_time = rtc->alarm_time;
+    struct 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)
+{
+    struct rtc_initial_count_t initial_count;
+
+    initial_count.count = frequency;
+    rtc->initial_count = initial_count;
+    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)
+{
+    struct rtc_current_count_t current_count;
+
+    current_count.count = count;
+    rtc->current_count = current_count;
+    return 0;
+}
+
+unsigned int rtc_timer_get_clock_count_value(void)
+{
+    return rtc->current_count.count;
+}
+
+int rtc_tick_interrupt_set(int enable)
+{
+    struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
+
+    interrupt_ctrl.tick_enable = enable;
+    rtc->interrupt_ctrl = interrupt_ctrl;
+    return 0;
+}
+
+int rtc_tick_interrupt_get(void)
+{
+    struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
+
+    return interrupt_ctrl.tick_enable;
+}
+
+int rtc_tick_interrupt_mode_set(rtc_tick_interrupt_mode_e mode)
+{
+    struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
+
+    interrupt_ctrl.tick_int_mode = mode;
+    rtc->interrupt_ctrl = interrupt_ctrl;
+    return 0;
+}
+
+rtc_tick_interrupt_mode_e rtc_tick_interrupt_mode_get(void)
+{
+    struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
+
+    return interrupt_ctrl.tick_int_mode;
+}
+
+int rtc_alarm_interrupt_set(int enable)
+{
+    struct 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)
+{
+    struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
+
+    return interrupt_ctrl.alarm_enable;
+}
+
+int rtc_alarm_interrupt_mask_set(struct rtc_mask_t mask)
+{
+    struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
+
+    interrupt_ctrl.alarm_compare_mask = *(uint8_t *)&mask;
+    rtc->interrupt_ctrl = interrupt_ctrl;
+    return 0;
+}
+
+struct rtc_mask_t rtc_alarm_interrupt_mask_get(void)
+{
+    struct rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
+
+    uint8_t compare_mask = interrupt_ctrl.alarm_compare_mask;
+
+    return *(struct rtc_mask_t *)&compare_mask;
+}
+
+int rtc_protect_set(int enable)
+{
+    struct rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
+
+    struct 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,
+    };
+
+    struct 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.timer_mask = *(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.timer_mask = *(uint8_t *)&mask;
+        register_ctrl.alarm_mask = *(uint8_t *)&mask;
+        register_ctrl.initial_count_mask = 1;
+        register_ctrl.interrupt_register_mask = 1;
+    }
+
+    rtc->register_ctrl = register_ctrl;
+    return 0;
+}
+
+int rtc_init(void)
+{
+    /* Reset RTC */
+    sysctl_reset(SYSCTL_RESET_RTC);
+    /* Enable RTC */
+    sysctl_clock_enable(SYSCTL_CLOCK_RTC);
+    rtc_timer_set_mode(RTC_TIMER_SETTING);
+    /* Unprotect RTC */
+    rtc_protect_set(0);
+    /* Set RTC clock frequency */
+    rtc_timer_set_clock_frequency(
+        sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0)
+    );
+    rtc_timer_set_clock_count_value(1);
+
+    /* Set RTC mode to timer running mode */
+    rtc_timer_set_mode(RTC_TIMER_RUNNING);
+    return 0;
+}

+ 135 - 0
lib/drivers/sha256.c

@@ -0,0 +1,135 @@
+/* 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.
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include "env/encoding.h"
+#include "sha256.h"
+#include "syscalls.h"
+#include "sysctl.h"
+
+volatile struct sha256_t* const sha256 = (volatile struct sha256_t*)SHA256_BASE_ADDR;
+
+#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
+#define _BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | (ROTL((x), 8) & 0x00ff00ffL))
+#define _BYTESWAP64(x) __byteswap64(x)
+
+static inline uint64_t __byteswap64(uint64_t x)
+{
+    uint32_t a = x >> 32;
+    uint32_t b = (uint32_t)x;
+
+    return ((uint64_t)_BYTESWAP(b) << 32) | (uint64_t)_BYTESWAP(a);
+}
+static const uint8_t padding[64] =
+{
+    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, 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, 0x02, 0x00};
+
+int sha256_init(uint8_t dma_en, uint32_t input_size, SHA256Context* sc)
+{
+    sysctl_clock_enable(SYSCTL_CLOCK_SHA);
+    sysctl_reset(SYSCTL_RESET_SHA);
+    input_size = (input_size + 64) / 64;
+    if (dma_en)
+        sha256->sha_input_ctrl |= 1;
+    else
+        sha256->sha_input_ctrl &= ~0x01;
+
+    sha256->sha_data_num = input_size;
+
+    sha256->sha_status |= 1 << 16; /*0 for little endian, 1 for big endian*/
+    sha256->sha_status |= 1; /*enable sha256*/
+
+    sc->totalLength = 0LL;
+    sc->hash[0] = 0x6a09e667L;
+    sc->hash[1] = 0xbb67ae85L;
+    sc->hash[2] = 0x3c6ef372L;
+    sc->hash[3] = 0xa54ff53aL;
+    sc->hash[4] = 0x510e527fL;
+    sc->hash[5] = 0x9b05688cL;
+    sc->hash[6] = 0x1f83d9abL;
+    sc->hash[7] = 0x5be0cd19L;
+    sc->bufferLength = 0L;
+    return 1;
+}
+
+void sha256_update(SHA256Context* sc, const void* vdata, uint32_t len)
+{
+    const uint8_t* data = vdata;
+    uint32_t bufferBytesLeft;
+    uint32_t bytesToCopy;
+    uint32_t i;
+
+    while (len)
+    {
+        bufferBytesLeft = 64L - sc->bufferLength;
+
+        bytesToCopy = bufferBytesLeft;
+        if (bytesToCopy > len)
+            bytesToCopy = len;
+
+        memcpy(&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy);
+
+        sc->totalLength += bytesToCopy * 8L;
+
+        sc->bufferLength += bytesToCopy;
+        data += bytesToCopy;
+        len -= bytesToCopy;
+
+        if (sc->bufferLength == 64L)
+        {
+            for (i = 0; i < 16; i++)
+            {
+                while (sha256->sha_input_ctrl & (1 << 8))
+                    ;
+                sha256->sha_data_in1 = sc->buffer.words[i];
+            }
+            sc->bufferLength = 0L;
+        }
+    }
+}
+
+void sha256_final(SHA256Context* sc, uint8_t hash[SHA256_HASH_SIZE])
+{
+    uint32_t bytesToPad;
+    uint64_t lengthPad;
+    int i;
+
+    bytesToPad = 120L - sc->bufferLength;
+    if (bytesToPad > 64L)
+        bytesToPad -= 64L;
+    lengthPad = _BYTESWAP64(sc->totalLength);
+    sha256_update(sc, padding, bytesToPad);
+    sha256_update(sc, &lengthPad, 8L);
+
+    while (!(sha256->sha_status & 0x01))
+        ;
+
+    if (hash)
+    {
+        for (i = 0; i < SHA256_HASH_WORDS; i++)
+        {
+            *((uint32_t*)hash) = sha256->sha_result[SHA256_HASH_WORDS - i - 1];
+            hash += 4;
+        }
+    }
+}

+ 615 - 0
lib/drivers/spi.c

@@ -0,0 +1,615 @@
+/* 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.
+ */
+#include "platform.h"
+#include "spi.h"
+#include "fpioa.h"
+#include "common.h"
+#include "sysctl.h"
+#include <stddef.h>
+#include <stdlib.h>
+
+#define     SPI_MAX_NUM     4
+
+volatile struct spi_t *const spi[4] = {
+    (volatile struct spi_t *)SPI0_BASE_ADDR,
+    (volatile struct spi_t *)SPI1_BASE_ADDR,
+    (volatile struct spi_t *)SPI_SLAVE_BASE_ADDR,
+    (volatile struct spi_t *)SPI3_BASE_ADDR
+};
+
+int spi_clk_init(uint8_t spi_bus){
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    sysctl_clock_enable(SYSCTL_CLOCK_SPI0 + spi_bus);
+    sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI0 + spi_bus, 0);
+    return 0;
+}
+
+int spi_init(uint8_t spi_bus){
+    spi_clk_init(spi_bus);
+    dmac_init();
+    return 0;
+}
+
+int spi_master_config(uint8_t spi_bus, spi_mode mode, spi_frame_format frame_format, size_t data_bit_length){
+    configASSERT(data_bit_length >= 4 && data_bit_length <= 32);
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+
+    uint8_t dfs_offset, frf_offset;
+    switch(spi_bus){
+        case 0:
+        case 1:
+            dfs_offset = 16;
+            frf_offset = 21;
+            break;
+        case 2:
+            configASSERT(!"Spi Bus 2 Not Support!");
+            break;
+        case 3:
+        default:
+            dfs_offset = 0;
+            frf_offset = 22;
+            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 struct spi_t *spi_adapter = spi[spi_bus];
+
+    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 = (mode << 6) | (frame_format << frf_offset) | ((data_bit_length - 1) << dfs_offset);
+    spi_adapter->spi_ctrlr0 = 0;
+    return 0;
+}
+
+void spi_trans_config(uint8_t spi_bus, size_t instruction_length, size_t address_length,
+                                size_t wait_cycles, spi_addr_inst_trans_mode trans_mode)
+{
+    configASSERT(wait_cycles < (1 << 5));
+    configASSERT(trans_mode < 3);
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+    uint32_t inst_l;
+    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) | trans_mode;
+}
+
+int spi_send_data(uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len)
+{
+    uint32_t index, fifo_len;
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+    spi_handle->ssienr = 0x01;
+    while (cmd_len){
+        spi_handle->dr[0] = *cmd_buff++;
+        cmd_len--;
+    }
+    fifo_len = 32 - spi_handle->txflr;
+    fifo_len = fifo_len < tx_len ? fifo_len : tx_len;
+    for (index = 0; index < fifo_len; index++)
+        spi_handle->dr[0] = *tx_buff++;
+    tx_len -= fifo_len;
+    spi_handle->ser = chip_sel;
+    while (tx_len) {
+        fifo_len = 32 - spi_handle->txflr;
+        fifo_len = fifo_len < tx_len ? fifo_len : tx_len;
+        for (index = 0; index < fifo_len; index++)
+            spi_handle->dr[0] = *tx_buff++;
+        tx_len -= fifo_len;
+    }
+    while ((spi_handle->sr & 0x05) != 0x04)
+        ;
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+    return 0;
+}
+
+int spi_send_data_dma(dmac_channel_number channel_num, uint8_t spi_bus, uint32_t chip_sel,
+                        uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    uint32_t *buf = malloc((cmd_len + tx_len) * sizeof(uint32_t));
+    int i;
+    for(i = 0; i < cmd_len; i++){
+        buf[i] = cmd_buff[i];
+    }
+
+    for(i = 0; i < tx_len; i++){
+        buf[cmd_len + i] = tx_buff[i];
+    }
+    spi_handle->dmacr = 0x2;    /*enable dma transmit*/
+    spi_handle->ssienr = 0x01;
+
+    sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 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, cmd_len + tx_len);
+    spi_handle->ser = chip_sel;
+    dmac_wait_done(channel_num);
+    free((void*)buf);
+
+
+    while ((spi_handle->sr & 0x05) != 0x04)
+        ;
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+    return 0;
+}
+
+int spi_normal_send_dma(dmac_channel_number channel_num, uint8_t spi_bus, uint32_t chip_sel,
+                        void *tx_buff, uint32_t tx_len, spi_transfer_width stw)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    uint32_t *buf = malloc((tx_len) * sizeof(uint32_t));
+    int i;
+    for(i = 0; i < tx_len; i++){
+        switch(stw){
+            case SPI_TRANS_SHORT:
+                buf[i] = ((uint16_t *)tx_buff)[i];
+            break;
+            case SPI_TRANS_INT:
+                buf[i] = ((uint32_t *)tx_buff)[i];
+            break;
+            break;
+            case SPI_TRANS_CHAR:
+            default:
+                buf[i] = ((uint8_t *)tx_buff)[i];
+            break;
+        }
+    }
+    spi_handle->dmacr = 0x2;    /*enable dma transmit*/
+    spi_handle->ssienr = 0x01;
+
+    sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 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 = chip_sel;
+    dmac_wait_done(channel_num);
+    free((void*)buf);
+
+    while ((spi_handle->sr & 0x05) != 0x04)
+        ;
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+    return 0;
+}
+
+int spi_receive_data(uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len)
+{
+    uint32_t index, fifo_len;
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    spi_handle->ctrlr1 = rx_len - 1;
+    spi_handle->ssienr = 0x01;
+    while (cmd_len--)
+        spi_handle->dr[0] = *cmd_buff++;
+    spi_handle->ser = chip_sel;
+    while (rx_len) {
+        fifo_len = spi_handle->rxflr;
+        fifo_len = fifo_len < rx_len ? fifo_len : rx_len;
+        for (index = 0; index < fifo_len; index++)
+            *rx_buff++ = spi_handle->dr[0];
+        rx_len -= fifo_len;
+    }
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+    return 0;
+}
+
+int spi_receive_data_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num,
+                            uint8_t spi_bus, uint32_t chip_sel, uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    uint32_t * write_cmd = malloc(sizeof(uint32_t) * (cmd_len + rx_len));
+    size_t i;
+    for (i = 0; i < cmd_len; i++)
+        write_cmd[i] = cmd_buff[i];
+
+    spi_handle->ctrlr1 = rx_len - 1;
+    spi_handle->dmacr = 0x3;
+    spi_handle->ssienr = 0x01;
+    spi_handle->ser = chip_sel;
+
+    sysctl_dma_select(w_channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 2);
+    sysctl_dma_select(r_channel_num, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_bus * 2);
+
+
+    dmac_set_single_mode(r_channel_num, (void *)(&spi_handle->dr[0]), write_cmd, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
+                            DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, rx_len);
+
+    dmac_set_single_mode(w_channel_num, write_cmd, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
+                            DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, cmd_len);
+
+    dmac_wait_done(w_channel_num);
+    dmac_wait_done(r_channel_num);
+
+    for(i = 0; i < rx_len; i++){
+        rx_buff[i] = write_cmd[i];
+    }
+    free(write_cmd);
+
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+    return 0;
+}
+
+
+int spi_special_receive_data(uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len)
+{
+    uint32_t index, fifo_len;
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    spi_handle->ctrlr1 = rx_len - 1;
+    spi_handle->ssienr = 0x01;
+    while (cmd_len--)
+        spi_handle->dr[0] = *cmd_buff++;
+    spi_handle->ser = chip_sel;
+    while (rx_len) {
+        fifo_len = spi_handle->rxflr;
+        fifo_len = fifo_len < rx_len ? fifo_len : rx_len;
+        for (index = 0; index < fifo_len; index++)
+            *rx_buff++ = spi_handle->dr[0];
+        rx_len -= fifo_len;
+    }
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+    return 0;
+}
+
+int spi_special_receive_data_dma(dmac_channel_number w_channel_num, dmac_channel_number r_channel_num,
+                                    uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len)
+{
+        configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+        volatile struct spi_t *spi_handle = spi[spi_bus];
+
+        uint32_t * write_cmd = malloc(sizeof(uint32_t) * (cmd_len + rx_len));
+        size_t i;
+        for (i = 0; i < cmd_len; i++)
+            write_cmd[i] = cmd_buff[i];
+
+        spi_handle->ctrlr1 = rx_len - 1;
+        spi_handle->dmacr = 0x3;
+        spi_handle->ssienr = 0x01;
+        spi_handle->ser = chip_sel;
+
+        sysctl_dma_select(w_channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 2);
+        sysctl_dma_select(r_channel_num, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_bus * 2);
+
+
+        dmac_set_single_mode(r_channel_num, (void *)(&spi_handle->dr[0]), write_cmd, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
+                                DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, rx_len);
+
+        dmac_set_single_mode(w_channel_num, write_cmd, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
+                                DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, cmd_len);
+
+        dmac_wait_done(w_channel_num);
+        dmac_wait_done(r_channel_num);
+
+        for(i = 0; i < rx_len; i++){
+            rx_buff[i] = write_cmd[i];
+        }
+        free(write_cmd);
+        spi_handle->ser = 0x00;
+        spi_handle->ssienr = 0x00;
+        return 0;
+
+}
+
+
+int spi_special_send_data(uint8_t spi_bus, uint32_t chip_sel, uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len)
+{
+    uint32_t index, fifo_len;
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    spi_handle->ssienr = 0x01;
+    while (cmd_len--)
+        spi_handle->dr[0] = *cmd_buff++;
+    fifo_len = 32 - spi_handle->txflr;
+    fifo_len = fifo_len < tx_len ? fifo_len : tx_len;
+    for (index = 0; index < fifo_len; index++)
+        spi_handle->dr[0] = *tx_buff++;
+    tx_len -= fifo_len;
+    spi_handle->ser = chip_sel;
+    while (tx_len) {
+        fifo_len = 32 - spi_handle->txflr;
+        fifo_len = fifo_len < tx_len ? fifo_len : tx_len;
+        for (index = 0; index < fifo_len; index++)
+            spi_handle->dr[0] = *tx_buff++;
+        tx_len -= fifo_len;
+    }
+    while ((spi_handle->sr & 0x05) != 0x04)
+        ;
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+    return 0;
+}
+
+int spi_special_send_data_dma(dmac_channel_number channel_num,uint8_t spi_bus, uint32_t chip_sel,
+                                uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    uint32_t *buf = malloc((cmd_len + tx_len) * sizeof(uint32_t));
+    int i;
+    for(i = 0; i < cmd_len; i++){
+        buf[i] = cmd_buff[i];
+    }
+
+    for(i = 0; i < tx_len; i++){
+        buf[cmd_len + i] = tx_buff[i];
+    }
+    spi_handle->dmacr = 0x2;    /*enable dma transmit*/
+    spi_handle->ssienr = 0x01;
+
+    sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 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, cmd_len + tx_len);
+    spi_handle->ser = chip_sel;
+    dmac_wait_done(channel_num);
+    free((void*)buf);
+
+    while ((spi_handle->sr & 0x05) != 0x04)
+        ;
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+    return 0;
+}
+
+int spi_fill_dma(dmac_channel_number channel_num,uint8_t spi_bus, uint32_t chip_sel,
+                                uint32_t *cmd_buff, uint32_t cmd_len)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    spi_handle->dmacr = 0x2;    /*enable dma transmit*/
+    spi_handle->ssienr = 0x01;
+
+    sysctl_dma_select(channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_bus * 2);
+    dmac_set_single_mode(channel_num, cmd_buff, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE,
+                                DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, cmd_len);
+    spi_handle->ser = chip_sel;
+    dmac_wait_done(channel_num);
+
+    while ((spi_handle->sr & 0x05) != 0x04)
+        ;
+    spi_handle->ser = 0x00;
+    spi_handle->ssienr = 0x00;
+    return 0;
+}
+
+void spi_set_tmod(uint8_t spi_bus, uint32_t tmod)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+    uint8_t tmod_offset = 0;
+    switch(spi_bus){
+    case 0:
+    case 1:
+        tmod_offset = 8;
+        break;
+    case 2:
+        configASSERT(!"Spi Bus 2 Not Support!");
+        break;
+    case 3:
+    default:
+        tmod_offset = 10;
+        break;
+    }
+
+    set_bit(&spi_handle->ctrlr0, 3 << tmod_offset, tmod << tmod_offset);
+}
+
+void spi_set_frame_format(uint8_t spi_bus, uint32_t spi_frf)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+    uint8_t frf_offset = 0;
+    switch(spi_bus){
+    case 0:
+    case 1:
+        frf_offset = 21;
+        break;
+    case 2:
+        configASSERT(!"Spi Bus 2 Not Support!");
+        break;
+    case 3:
+    default:
+        frf_offset = 22;
+        break;
+    }
+
+    set_bit(&spi_handle->ctrlr0, 3 << frf_offset, spi_frf << frf_offset);
+}
+
+int spi_get_frame_format(uint8_t spi_bus)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+    uint8_t frf_offset = 0;
+    switch(spi_bus){
+    case 0:
+    case 1:
+        frf_offset = 21;
+        break;
+    case 2:
+        configASSERT(!"Spi Bus 2 Not Support!");
+        break;
+    case 3:
+    default:
+        frf_offset = 22;
+        break;
+    }
+    return ((spi_handle->ctrlr0 >> frf_offset) & 0x03);
+}
+
+/*
+    SPI MODE0-3
+    Serial Clock Polarity
+    Serial Clock Phase
+*/
+void spi_set_work_mode(uint8_t spi_bus, spi_mode mode)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+    set_bit(&spi_handle->ctrlr0, 0x3 << 6, mode << 6);
+}
+
+void spi_set_frame_size(uint8_t spi_bus, uint32_t dfs)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    uint8_t dfs_offset;
+    switch(spi_bus){
+        case 0:
+        case 1:
+            dfs_offset = 16;
+            break;
+        case 2:
+            configASSERT(!"Spi Bus 2 Not Support!");
+            break;
+        case 3:
+        default:
+            dfs_offset = 0;
+            break;
+    }
+    int frame_format = spi_get_frame_format(spi_bus);
+    switch (frame_format)
+    {
+    case SPI_FF_DUAL:
+        configASSERT(dfs % 2 == 0);
+        break;
+    case SPI_FF_QUAD:
+        configASSERT(dfs % 4 == 0);
+        break;
+    case SPI_FF_OCTAL:
+        configASSERT(dfs % 8 == 0);
+        break;
+    default:
+        break;
+    }
+    set_bit(&spi_handle->ctrlr0, 0x1F << dfs_offset, (dfs-1) << dfs_offset);
+}
+
+void spi_set_wait_cycles(uint8_t spi_bus, uint32_t wcycles)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    configASSERT(wcycles < (1 << 5));
+    int frame_format = spi_get_frame_format(spi_bus);
+    configASSERT(frame_format != SPI_FF_STANDARD);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    set_bit(&spi_handle->spi_ctrlr0, 0x1F << 11, wcycles << 11);
+}
+
+void spi_set_inst_length(uint8_t spi_bus, uint32_t instruction_length)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    int frame_format = spi_get_frame_format(spi_bus);
+    configASSERT(frame_format != SPI_FF_STANDARD);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+
+    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;
+    }
+
+    set_bit(&spi_handle->spi_ctrlr0, 0x3 << 8, inst_l << 8);
+}
+
+void spi_set_address_length(uint8_t spi_bus, uint32_t address_length)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    int frame_format = spi_get_frame_format(spi_bus);
+    configASSERT(frame_format != SPI_FF_STANDARD);
+    configASSERT(address_length % 4 == 0 && address_length <= 60);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+    uint32_t addr_l = address_length / 4;
+    set_bit(&spi_handle->spi_ctrlr0, 0xF << 2, addr_l << 2);
+}
+
+void spi_set_trans_mode(uint8_t spi_bus, spi_addr_inst_trans_mode trans_mode)
+{
+    configASSERT(spi_bus < SPI_MAX_NUM && spi_bus != 2);
+    int frame_format = spi_get_frame_format(spi_bus);
+    configASSERT(frame_format != SPI_FF_STANDARD);
+    volatile struct spi_t *spi_handle = spi[spi_bus];
+    set_bit(&spi_handle->spi_ctrlr0, 0x3 << 0, trans_mode << 0);
+}
+

+ 69 - 0
lib/drivers/sysclock.c

@@ -0,0 +1,69 @@
+/* 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.
+ */
+#include "sysclock.h"
+#include "stdio.h"
+#include "sysctl.h"
+#include "uarths.h"
+
+void sys_clock_init()
+{
+    sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_IN0);
+
+    sysctl_pll_enable(SYSCTL_PLL0);
+    sysctl_pll_set_freq(SYSCTL_PLL0, SYSCTL_SOURCE_IN0, PLL0_OUTPUT_FREQ);
+    while (sysctl_pll_is_lock(SYSCTL_PLL0) == 0)
+        sysctl_pll_clear_slip(SYSCTL_PLL0);
+    sysctl_clock_enable(SYSCTL_CLOCK_PLL0);
+    sysctl->clk_sel0.aclk_divider_sel = 0;
+    sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_PLL0);
+
+    sysctl_pll_enable(SYSCTL_PLL1);
+    sysctl_pll_set_freq(SYSCTL_PLL1, SYSCTL_SOURCE_IN0, PLL1_OUTPUT_FREQ);
+    while (sysctl_pll_is_lock(SYSCTL_PLL1) == 0)
+        sysctl_pll_clear_slip(SYSCTL_PLL1);
+    sysctl_clock_enable(SYSCTL_CLOCK_PLL1);
+
+    sysctl_pll_enable(SYSCTL_PLL2);
+    sysctl_pll_set_freq(SYSCTL_PLL2, SYSCTL_SOURCE_IN0, PLL2_OUTPUT_FREQ);
+    while (sysctl_pll_is_lock(SYSCTL_PLL2) == 0)
+        sysctl_pll_clear_slip(SYSCTL_PLL2);
+    sysctl_clock_enable(SYSCTL_CLOCK_PLL2);
+}
+
+uint32_t system_set_cpu_frequency(uint32_t frequency)
+{
+    sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_IN0);
+    sysctl->pll0.pll_reset0 = 1;
+
+    uint32_t result = sysctl_pll_set_freq(SYSCTL_PLL0, SYSCTL_SOURCE_IN0, frequency * 2);
+    sysctl->pll0.pll_reset0 = 0;
+    while (1)
+    {
+        uint32_t lock = sysctl->pll_lock.pll_lock0 & 0x3;
+        if (lock == 0x3)
+        {
+            break;
+        }
+        else
+        {
+            sysctl->pll_lock.pll_slip_clear0 = 1;
+        }
+    }
+
+    sysctl->pll0.pll_out_en0 = 1;
+    sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_PLL0);
+    uart_init();
+    return result;
+}

+ 1726 - 0
lib/drivers/sysctl.c

@@ -0,0 +1,1726 @@
+/* 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.
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include "sysctl.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 struct sysctl_t *const sysctl = (volatile struct 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(enum sysctl_reset_e 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(enum sysctl_reset_e reset)
+{
+    sysctl_reset_ctl(reset, 1);
+    sysctl_reset_ctl(reset, 0);
+}
+
+static int sysctl_clock_bus_en(enum sysctl_clock_e 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(enum sysctl_clock_e 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(enum sysctl_clock_e 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(enum sysctl_clock_e clock)
+{
+    if (clock >= SYSCTL_CLOCK_MAX)
+        return -1;
+    sysctl_clock_bus_en(clock, 0);
+    sysctl_clock_device_en(clock, 0);
+    return 0;
+}
+
+int sysctl_clock_set_threshold(enum sysctl_threshold_e which, int threshold)
+{
+    switch (which)
+    {
+        /*
+         * 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:
+            break;
+    }
+
+    return 0;
+}
+
+int sysctl_clock_get_threshold(enum sysctl_threshold_e 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(enum sysctl_clock_select_e which, int select)
+{
+    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_PLL3_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:
+            break;
+    }
+
+    return 0;
+}
+
+int sysctl_clock_get_clock_select(enum sysctl_clock_select_e 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_PLL3_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(enum sysctl_clock_source_e 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 = sysctl_clock_get_freq(SYSCTL_CLOCK_ACLK);
+            break;
+
+        default:
+            result = 0;
+            break;
+    }
+    return result;
+}
+
+int sysctl_pll_is_lock(enum sysctl_pll_e pll)
+{
+    /*
+     * All bit enable means PLL lock
+     *
+     * struct pll_lock_t
+     * {
+     *         uint8_t overflow : 1;
+     *         uint8_t rfslip : 1;
+     *         uint8_t fbslip : 1;
+     * };
+     *
+     */
+
+    uint8_t lock = 0;
+
+    if (pll >= SYSCTL_PLL_MAX)
+        return 0;
+
+    switch (pll)
+    {
+        case SYSCTL_PLL0:
+            lock = sysctl->pll_lock.pll_lock0;
+            break;
+
+        case SYSCTL_PLL1:
+            lock = sysctl->pll_lock.pll_lock1;
+            break;
+
+        case SYSCTL_PLL2:
+            lock = sysctl->pll_lock.pll_lock2;
+            break;
+
+        default:
+            break;
+    }
+
+    if (lock == 3)
+        return 1;
+
+    return 0;
+}
+
+int sysctl_pll_clear_slip(enum sysctl_pll_e 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(enum sysctl_pll_e 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;
+            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;
+            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;
+            sysctl->pll2.pll_reset2 = 0;
+            break;
+
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+int sysctl_pll_disable(enum sysctl_pll_e 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(enum sysctl_pll_e 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 frequency 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 frequency
+     * FOUT = FIN / NR * NF / OD
+     */
+    freq_out = (double)freq_in / (double)nr * (double)nf / (double)od;
+    return freq_out;
+}
+
+uint32_t sysctl_pll_set_freq(enum sysctl_pll_e pll, enum sysctl_clock_source_e 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 frequency
+             */
+            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 frequency
+             */
+            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 == -1)
+    {
+        printf("NR\tNF\tOD\tNB\tFvco\t\terror\n");
+        printf("------------------------------------------------------\n");
+    }
+    else 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;
+            printf("%d\t%lld\t%d\t%d\t%e\t%#+g\n", nrx, nfx, no, nb, fvco, err);
+        }
+    }
+    if (!found)
+    {
+        printf("Error:  No workable settings found.\n");
+        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)))
+    {
+        printf("Error:  No appropriate ratio found.\n");
+        return 0;
+    }
+
+#ifdef CONFIG_PLL_DEBUG_ENABLE
+    printf("NR = %d\n", nrx);
+    printf("NF = %lld\n", nfx);
+    printf("OD = %d\n", no);
+    printf("NB = %d\n", nb);
+
+    printf("\n");
+    printf("Fin  = %g\n", fin);
+    printf("Fvco = %g\n", fvco);
+    printf("Fout = %g\n", fvco / no);
+    printf("error = %+g\n", err);
+
+    printf("\n");
+    printf("CLKR[3:0] = %02x\n", nrx - 1);
+    printf("CLKF[5:0] = %02x\n", (unsigned int)nfx - 1);
+    printf("CLKOD[3:0] = %02x\n", no - 1);
+    printf("BWADJ[5:0] = %02x\n", nb - 1);
+#endif /* CONFIG_PLL_DEBUG_ENABLE */
+
+    /*
+     * Begin write PLL registers' value,
+     * Using atomic write method.
+     */
+    struct sysctl_pll0_t pll0;
+    struct sysctl_pll1_t pll1;
+    struct 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 sysctl_clock_get_freq(enum sysctl_clock_e clock)
+{
+    uint32_t source = 0;
+    uint32_t result = 0;
+
+    switch (clock)
+    {
+        /*
+         * 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 = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0);
+            result = source;
+            break;
+        case SYSCTL_CLOCK_UART1:
+            source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0);
+            result = source;
+            break;
+        case SYSCTL_CLOCK_UART2:
+            source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0);
+            result = source;
+            break;
+        case SYSCTL_CLOCK_UART3:
+            source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0);
+            result = source;
+            break;
+        case SYSCTL_CLOCK_FPIOA:
+            source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0);
+            result = source;
+            break;
+        case SYSCTL_CLOCK_SHA:
+            source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0);
+            result = source;
+            break;
+
+        /*
+         * These clock under APB1 clock domain.
+         * They are using even divider.
+         */
+        case SYSCTL_CLOCK_AES:
+            source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB1);
+            result = source;
+            break;
+        case SYSCTL_CLOCK_OTP:
+            source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB1);
+            result = source;
+            break;
+        case SYSCTL_CLOCK_RTC:
+            source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB1);
+            result = source;
+            break;
+
+        /*
+         * These clock under APB2 clock domain.
+         * They are using even divider.
+         */
+        /*
+         * Do nothing.
+         */
+        default:
+            break;
+    }
+    return result;
+}
+
+int sysctl_dma_select(enum sysctl_dma_channel_e channel, enum sysctl_dma_select_e select)
+{
+    struct sysctl_dma_sel0_t dma_sel0;
+    struct 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.
+     */
+    struct sysctl_pll0_t pll0;
+    struct sysctl_pll1_t pll1;
+    struct 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;
+}

+ 214 - 0
lib/drivers/timer.c

@@ -0,0 +1,214 @@
+/* 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.
+ */
+#include "timer.h"
+#include "sysctl.h"
+#include "stddef.h"
+#include "common.h"
+#include "plic.h"
+#include "io.h"
+
+volatile struct timer_t *const timer[3] =
+{
+    (volatile struct timer_t *)TIMER0_BASE_ADDR,
+    (volatile struct timer_t *)TIMER1_BASE_ADDR,
+    (volatile struct timer_t *)TIMER2_BASE_ADDR
+};
+
+void timer_init(uint32_t tim)
+{
+    sysctl_clock_enable(SYSCTL_CLOCK_TIMER0 + tim);
+}
+
+void timer_set_clock_div(uint32_t tim, uint32_t div)
+{
+    sysctl_clock_set_threshold(tim == 0 ? SYSCTL_THRESHOLD_TIMER0 :
+        tim == 1 ? SYSCTL_THRESHOLD_TIMER1 :
+        SYSCTL_THRESHOLD_TIMER2, div);
+}
+
+void timer_enable(uint32_t tim, uint32_t channel)
+{
+    timer[tim]->channel[channel].control |= TIMER_CR_ENABLE;
+}
+
+void timer_disable(uint32_t tim, uint32_t channel)
+{
+    timer[tim]->channel[channel].control &= (~TIMER_CR_ENABLE);
+}
+
+void timer_enable_pwm(uint32_t tim, uint32_t channel)
+{
+    timer[tim]->channel[channel].control |= TIMER_CR_PWM_ENABLE;
+}
+
+void timer_disable_pwm(uint32_t tim, uint32_t channel)
+{
+    timer[tim]->channel[channel].control &= (~TIMER_CR_PWM_ENABLE);
+}
+
+void timer_enable_interrupt(uint32_t tim, uint32_t channel)
+{
+    timer[tim]->channel[channel].control &= (~TIMER_CR_INTERRUPT_MASK);
+}
+
+void timer_disable_interrupt(uint32_t tim, uint32_t channel)
+{
+    timer[tim]->channel[channel].control |= TIMER_CR_INTERRUPT_MASK;
+}
+
+void timer_set_mode(uint32_t tim, uint32_t channel, uint32_t mode)
+{
+    timer[tim]->channel[channel].control &= (~TIMER_CR_MODE_MASK);
+    timer[tim]->channel[channel].control |= mode;
+}
+
+void timer_set_reload(uint32_t tim, uint32_t channel, uint32_t count)
+{
+    timer[tim]->channel[channel].load_count = count;
+}
+
+void timer_set_reload2(uint32_t tim, uint32_t channel, uint32_t count)
+{
+    timer[tim]->load_count2[channel] = count;
+}
+
+uint32_t timer_get_count(uint32_t tim, uint32_t channel)
+{
+    return timer[tim]->channel[channel].current_value;
+}
+
+uint32_t timer_get_reload(uint32_t tim, uint32_t channel)
+{
+    return timer[tim]->channel[channel].load_count;
+}
+
+uint32_t timer_get_reload2(uint32_t tim, uint32_t channel)
+{
+    return timer[tim]->load_count2[channel];
+}
+
+uint32_t timer_get_interrupt_status(uint32_t tim)
+{
+    return timer[tim]->intr_stat;
+}
+
+uint32_t timer_get_raw_interrupt_status(uint32_t tim)
+{
+    return timer[tim]->raw_intr_stat;
+}
+
+uint32_t timer_channel_get_interrupt_status(uint32_t tim, uint32_t channel)
+{
+    return timer[tim]->channel[channel].intr_stat;
+}
+
+void timer_clear_interrupt(uint32_t tim)
+{
+    timer[tim]->eoi = timer[tim]->eoi;
+}
+
+void timer_channel_clear_interrupt(uint32_t tim, uint32_t channel)
+{
+    timer[tim]->channel[channel].eoi = timer[tim]->channel[channel].eoi;
+}
+
+void timer_set_enable(uint32_t tim, uint32_t channel, uint32_t enable){
+    if (enable)
+        timer[tim]->channel[channel].control = TIMER_CR_USER_MODE | TIMER_CR_ENABLE;
+    else
+        timer[tim]->channel[channel].control = TIMER_CR_INTERRUPT_MASK;
+}
+
+size_t timer_set_interval(uint32_t tim, uint32_t channel, size_t nanoseconds)
+{
+    uint32_t clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + tim);
+
+    double min_step = 1e9 / clk_freq;
+    size_t value = (size_t)(nanoseconds / min_step);
+    configASSERT(value > 0 && value < UINT32_MAX);
+    timer[tim]->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 tim;
+    for (tim = 0; tim < 3; tim++)
+    {
+        if (parm == timer[tim])
+            break;
+    }
+
+    uint32_t channel = timer[tim]->intr_stat;
+    size_t i = 0;
+    for (i = 0; i < 4; i++)
+    {
+        if (channel & 1)
+        {
+            if (time_irq[tim][i])
+                (time_irq[tim][i])();
+            break;
+        }
+
+        channel >>= 1;
+    }
+
+    readl(&timer[tim]->eoi);
+    return 0;
+}
+
+void timer_set_irq(uint32_t tim, uint32_t channel, void(*func)(), uint32_t priority)
+{
+    time_irq[tim][channel] = func;
+    if (channel < 2)
+    {
+        plic_set_priority(IRQN_TIMER0A_INTERRUPT + tim * 2, priority);
+        plic_irq_register(IRQN_TIMER0A_INTERRUPT + tim * 2, timer_isr, (void *)timer[tim]);
+        plic_irq_enable(IRQN_TIMER0A_INTERRUPT + tim * 2);
+    }
+    else
+    {
+        plic_set_priority(IRQN_TIMER0B_INTERRUPT + tim * 2, priority);
+        plic_irq_register(IRQN_TIMER0B_INTERRUPT + tim * 2, timer_isr, NULL);
+        plic_irq_enable(IRQN_TIMER0B_INTERRUPT + tim * 2);
+    }
+}
+
+void pwm_set_enable(uint32_t tim, uint32_t channel, int enable)
+{
+    if (enable)
+        timer[tim]->channel[channel].control = TIMER_CR_INTERRUPT_MASK | TIMER_CR_PWM_ENABLE | TIMER_CR_USER_MODE | TIMER_CR_ENABLE;
+    else
+        timer[tim]->channel[channel].control = TIMER_CR_INTERRUPT_MASK;
+}
+
+double pwm_set_frequency(uint32_t tim, uint32_t channel, double frequency, double duty)
+{
+    uint32_t clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + tim);
+
+    int32_t periods = (int32_t)(clk_freq / frequency);
+    configASSERT(periods > 0 && periods <= INT32_MAX);
+    frequency = clk_freq / (double)periods;
+
+    uint32_t percent = (uint32_t)(duty * periods);
+    timer[tim]->channel[channel].load_count = periods - percent;
+    timer[tim]->load_count2[channel] = percent;
+
+    return frequency;
+}
+

+ 194 - 0
lib/drivers/uart.c

@@ -0,0 +1,194 @@
+/* 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.
+ */
+#include <stdlib.h>
+#include <stdint.h>
+#include "plic.h"
+#include "sysctl.h"
+#include "uart.h"
+#include "common.h"
+#include "atomic.h"
+
+#define __UART_BRATE_CONST  16
+
+typedef struct
+{
+    uart_t *uart;
+    const uart_info_t *uart_info;
+    uint32_t uart_status;
+} uart_devinfo_t;
+
+volatile uart_t* const  uart[3] =
+{
+    (volatile uart_t*)UART1_BASE_ADDR,
+    (volatile uart_t*)UART2_BASE_ADDR,
+    (volatile uart_t*)UART3_BASE_ADDR
+};
+
+#define RING_BUFF_LEN 64U
+
+typedef struct
+{
+    size_t head;
+    size_t tail;
+    size_t length;
+    char ring_buff[RING_BUFF_LEN];
+} ring_buff_t;
+
+ring_buff_t *ring_recv[3] = {NULL, NULL, NULL};
+
+static int write_ringbuff(uint8_t channel, uint8_t rdata)
+{
+    ring_buff_t *rb = ring_recv[channel];
+
+    if (rb->length >= RING_BUFF_LEN)
+    {
+        return -1;
+    }
+    rb->ring_buff[rb->tail] = rdata;
+    rb->tail = (rb->tail + 1) % RING_BUFF_LEN;
+    atomic_add(&rb->length, 1);
+    return 0;
+}
+
+static int read_ringbuff(uint8_t channel, char *rdata, size_t len)
+{
+    ring_buff_t *rb = ring_recv[channel];
+    size_t cnt = 0;
+    while ((len--) && rb->length)
+    {
+        *(rdata++) = rb->ring_buff[rb->head];
+        rb->head = (rb->head + 1) % RING_BUFF_LEN;
+        atomic_add(&rb->length, -1);
+        cnt++;
+    }
+    return cnt;
+}
+
+static int on_irq_apbuart_recv(void *param)
+{
+    int i = 0;
+    for (i = 0; i < 3; i++)
+    {
+        if (param == uart[i])
+            break;
+    }
+
+    while (uart[i]->LSR & 1)
+    {
+        write_ringbuff(i, ((uint8_t)(uart[i]->RBR & 0xff)));
+    }
+    return 0;
+}
+
+static int uartapb_putc(uint8_t channel, char c)
+{
+    while (!(uart[channel]->LSR & (1u << 6)))
+        continue;
+    uart[channel]->THR = c;
+    return 0;
+}
+
+int uartapb_getc(uint8_t channel)
+{
+    while (!(uart[channel]->LSR & 1))
+        continue;
+
+    return (char)(uart[channel]->RBR & 0xff);
+}
+
+
+int uart_read(uint8_t channel, char* buffer, size_t len)
+{
+    return read_ringbuff(channel, buffer, len);
+}
+
+int uart_write(uint8_t channel, const char* buffer, size_t len)
+{
+    int write = 0;
+    while (write < len)
+    {
+        uartapb_putc(channel, *buffer++);
+        write++;
+    }
+
+    return write;
+}
+
+void uart_config(uint8_t channel, size_t baud_rate, size_t data_width, uart_stopbit stopbit, uart_parity parity)
+{
+
+    configASSERT(data_width >= 5 && data_width <= 8);
+    if (data_width == 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 parity_val;
+    switch (parity)
+    {
+        case UART_PARITY_None:
+            parity_val = 0;
+            break;
+        case UART_PARITY_Odd:
+            parity_val = 1;
+            break;
+        case UART_PARITY_Even:
+            parity_val = 3;
+            break;
+        default:
+            configASSERT(!"Invalid parity");
+            break;
+    }
+
+    uint32_t freq = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0);
+    uint32_t u16Divider = (freq + __UART_BRATE_CONST * baud_rate / 2) /
+        (__UART_BRATE_CONST * baud_rate);
+
+    /* 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]->DLL = u16Divider & 0xFF;
+    uart[channel]->DLH = u16Divider >> 8;
+    uart[channel]->LCR = 0;
+    uart[channel]->LCR = (data_width - 5) | (stopbit_val << 2) | (parity_val << 3);
+    uart[channel]->LCR &= ~(1u << 7);
+    uart[channel]->MCR &= ~3;
+    uart[channel]->IER = 1;     /*RX INT enable*/
+}
+
+void uartapb_init(uint8_t channel)
+{
+    sysctl_clock_enable(SYSCTL_CLOCK_UART1 + channel);
+
+    ring_buff_t *rb = malloc(sizeof(ring_buff_t));
+    rb->head = 0;
+    rb->tail = 0;
+    rb->length = 0;
+    ring_recv[channel] = rb;
+    plic_irq_register(IRQN_UART1_INTERRUPT + channel, on_irq_apbuart_recv, (void *)uart[channel]);
+    plic_set_priority(IRQN_UART1_INTERRUPT + channel, 1);
+    plic_irq_enable(IRQN_UART1_INTERRUPT);
+}

+ 97 - 0
lib/drivers/uarths.c

@@ -0,0 +1,97 @@
+/* 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.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include "uarths.h"
+#include "sysctl.h"
+#include "env/encoding.h"
+
+volatile struct uarths_t *const uarths = (volatile struct uarths_t *)UARTHS_BASE_ADDR;
+
+static inline int uart_putc(char c)
+{
+    /* Read hart id */
+    unsigned long hart_id = read_csr(mhartid);
+    /* Set print data reg */
+    volatile uint32_t *reg = (volatile uint32_t *)0x50440080UL;
+    /* Push data out */
+    if (hart_id == 0)
+    {
+        /* Select core 0 data reg */
+        *reg = (0UL << 30) | c;
+    }
+    else
+    {
+        /* Select core 1 data reg */
+        *reg = (1UL << 30) | c;
+    }
+
+    /* Convert to DOS style (CRLF terminated) */
+    if (c == '\n')
+    {
+        while (uarths->txdata.full)
+            continue;
+        uarths->txdata.data = '\r';
+    }
+    while (uarths->txdata.full)
+        continue;
+    uarths->txdata.data = c;
+
+    return 0;
+}
+
+int uart_getc(void)
+{
+    /* while not empty */
+    struct uarths_rxdata_t recv = uarths->rxdata;
+
+    if (recv.empty)
+        return EOF;
+    else
+        return recv.data;
+}
+
+int uart_putchar(char c)
+{
+    return uart_putc(c);
+}
+
+int uart_puts(const char *s)
+{
+    while (*s)
+        if (uart_putc(*s++) != 0)
+            return -1;
+    return 0;
+}
+
+int uart_init()
+{
+    uint32_t freq = sysctl_clock_get_freq(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;
+
+    return 0;
+}

+ 120 - 0
lib/drivers/wdt.c

@@ -0,0 +1,120 @@
+/* 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.
+ */
+#include "wdt.h"
+#include "platform.h"
+#include "stddef.h"
+#include "common.h"
+#include "sysctl.h"
+#include "plic.h"
+
+plic_irq_callback_t wdt_irq[2];
+
+volatile struct wdt_t *const wdt[2] =
+{
+    (volatile struct wdt_t *)WDT0_BASE_ADDR,
+    (volatile struct wdt_t *)WDT1_BASE_ADDR
+};
+
+void wdt_feed(uint8_t id)
+{
+    wdt[id]->crr = WDT_CRR_MASK;
+}
+
+void wdt_enable(uint8_t id)
+{
+    wdt[id]->crr = WDT_CRR_MASK;
+    wdt[id]->cr |= WDT_CR_ENABLE;
+}
+
+void wdt_disable(uint8_t id)
+{
+    wdt[id]->crr = WDT_CRR_MASK;
+    wdt[id]->cr &= (~WDT_CR_ENABLE);
+}
+
+void wdt_timeout_set(uint8_t id, uint8_t timeout)
+{
+    wdt[id]->torr = WDT_TORR_TOP(timeout);
+}
+
+void wdt_response_mode(uint8_t id, uint8_t mode)
+{
+    wdt[id]->cr &= (~WDT_CR_RMOD_MASK);
+    wdt[id]->cr |= mode;
+}
+
+void wdt_interrupt_clear(uint8_t id)
+{
+    wdt[id]->eoi = wdt[id]->eoi;
+}
+
+void wdt_set_irq(uint8_t id, plic_irq_callback_t on_irq)
+{
+    wdt_irq[id] = on_irq;
+}
+
+size_t wdt_get_pclk(uint8_t id)
+{
+    return id ? sysctl_clock_get_freq(SYSCTL_CLOCK_WDT1) : sysctl_clock_get_freq(SYSCTL_CLOCK_WDT0);
+}
+
+ssize_t log_2(size_t x)
+{
+    ssize_t i = 0;
+    for (i = sizeof(size_t) * 8; i >= 0; i--)
+    {
+        if ((x >> i) & 0x1)
+        {
+            break;
+        }
+    }
+    return i;
+}
+
+uint8_t wdt_get_top(uint8_t id, size_t timeout_ms)
+{
+    size_t wdt_clk = wdt_get_pclk(id);
+    size_t ret = (timeout_ms * wdt_clk / 1000) >> 16;
+    if (ret)
+        ret = log_2(ret);
+    if (ret > 0xf)
+        ret = 0xf;
+    return (uint8_t)ret;
+}
+
+
+int wdt_start(uint8_t id, size_t toms)
+{
+    wdt_disable(id);
+    wdt_interrupt_clear(id);
+    plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, wdt_irq[id], NULL);
+    plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1);
+    plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT);
+
+    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);
+    wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT);
+    uint8_t m_top = wdt_get_top(id, toms);
+    wdt_timeout_set(id, m_top);
+    wdt_enable(id);
+    return 0;
+}
+
+void wdt_stop(uint8_t id)
+{
+    wdt_disable(id);
+}
+

+ 366 - 0
lib/firmware/include/font.h

@@ -0,0 +1,366 @@
+/* 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.
+ */
+#ifndef _FONT_H_
+#define _FONT_H_
+
+#include <stdint.h>
+
+uint8_t const ascii0816[] =
+{
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD,
+    0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF,
+    0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE,
+    0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+    0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
+    0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD,
+    0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1E, 0x0E,
+    0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30,
+    0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63,
+    0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8,
+    0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0E,
+    0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+    0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB,
+    0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6,
+    0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
+    0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0,
+    0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C,
+    0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C,
+    0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x06, 0x86, 0xC6, 0x7C,
+    0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18,
+    0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C,
+    0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
+    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E,
+    0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xD6, 0xD6, 0xC6, 0xC6, 0x6C, 0x38,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
+    0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE,
+    0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0,
+    0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18,
+    0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
+    0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+    0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00,
+    0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+    0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE,
+    0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
+    0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0,
+    0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x6C,
+    0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68,
+    0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66,
+    0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x0C,
+    0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60,
+    0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE,
+    0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66,
+    0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C,
+    0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C,
+    0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
+    0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0xEE, 0x6C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38,
+    0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66,
+    0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 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, 0x00, 0x00,
+    0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60,
+    0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC,
+    0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x60,
+    0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0xE0, 0x60,
+    0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6,
+    0xD6, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66,
+    0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0x60, 0x60, 0xF0,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60,
+    0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
+    0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
+    0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
+    0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6,
+    0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66,
+    0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00,
+    0x00, 0x00, 0xCC, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE,
+    0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C,
+    0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xCC, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38,
+    0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06,
+    0x3C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE,
+    0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00,
+    0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66,
+    0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6,
+    0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, 0x00,
+    0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36,
+    0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x6C,
+    0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+    0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00,
+    0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00,
+    0x00, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3C,
+    0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
+    0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xCC, 0xCC,
+    0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0xD8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30,
+    0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC,
+    0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+    0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C,
+    0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0,
+    0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xDC, 0x86, 0x0C,
+    0x18, 0x3E, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30,
+    0x66, 0xCE, 0x9E, 0x3E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+    0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6C, 0xD8, 0x6C, 0x36, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x6C, 0x36,
+    0x6C, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
+    0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+    0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+    0x55, 0xAA, 0x55, 0xAA, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
+    0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
+    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+    0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+    0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xD8, 0xCC, 0xC6, 0xC6, 0xC6, 0xCC,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0,
+    0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8,
+    0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66,
+    0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+    0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66,
+    0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xDB, 0xDB, 0xF3, 0x7E, 0x60, 0xC0,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60,
+    0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C,
+    0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18,
+    0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+    0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00,
+    0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C,
+    0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0C, 0x0C,
+    0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD8, 0x30, 0x60, 0xC8, 0xF8, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00};
+
+#endif
+

+ 82 - 0
lib/firmware/include/lcd.h

@@ -0,0 +1,82 @@
+/* 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.
+ */
+#ifndef _LCD_H_
+#define _LCD_H_
+
+#include <stdint.h>
+
+/* clang-format off */
+#define LCD_X_MAX   (320)
+#define LCD_Y_MAX   (480)
+
+#define BLACK       0x0000
+#define NAVY        0x000F
+#define DARKGREEN   0x03E0
+#define DARKCYAN    0x03EF
+#define MAROON      0x7800
+#define PURPLE      0x780F
+#define OLIVE       0x7BE0
+#define LIGHTGREY   0xC618
+#define DARKGREY    0x7BEF
+#define BLUE        0x001F
+#define GREEN       0x07E0
+#define CYAN        0x07FF
+#define RED         0xF800
+#define MAGENTA     0xF81F
+#define YELLOW      0xFFE0
+#define WHITE       0xFFFF
+#define ORANGE      0xFD20
+#define GREENYELLOW 0xAFE5
+#define PINK        0xF81F
+#define USER_COLOR  0xAA55
+/* clang-format on */
+
+enum lcd_dir_t
+{
+    DIR_XY_RLUD = 0x00,
+    DIR_YX_RLUD = 0x20,
+    DIR_XY_LRUD = 0x40,
+    DIR_YX_LRUD = 0x60,
+    DIR_XY_RLDU = 0x80,
+    DIR_YX_RLDU = 0xA0,
+    DIR_XY_LRDU = 0xC0,
+    DIR_YX_LRDU = 0xE0,
+    DIR_XY_MASK = 0x20,
+    DIR_MASK = 0xE0,
+};
+
+typedef struct
+{
+    uint8_t mode;
+    uint8_t dir;
+    uint16_t width;
+    uint16_t height;
+} lcd_ctl_t;
+
+int lcd_busy(void);
+void lcd_polling_enable(void);
+void lcd_interrupt_enable(void);
+void lcd_init(void);
+void lcd_clear(uint16_t color);
+void lcd_set_direction(enum lcd_dir_t dir);
+void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
+void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color);
+void lcd_draw_string(uint16_t x, uint16_t y, char *str, uint16_t color);
+void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr);
+void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color);
+void lcd_ram_draw_string(char *str, uint32_t *ptr, uint16_t font_color, uint16_t bg_color);
+
+#endif
+

+ 113 - 0
lib/firmware/include/nt35310.h

@@ -0,0 +1,113 @@
+/* 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.
+ */
+#ifndef _NT35310_H_
+#define _NT35310_H_
+
+#include <stdint.h>
+
+/* clang-format off */
+#define NO_OPERATION            0x00
+#define SOFTWARE_RESET          0x01
+#define READ_ID                 0x04
+#define READ_STATUS             0x09
+#define READ_POWER_MODE         0x0A
+#define READ_MADCTL             0x0B
+#define READ_PIXEL_FORMAT       0x0C
+#define READ_IMAGE_FORMAT       0x0D
+#define READ_SIGNAL_MODE        0x0E
+#define READ_SELT_DIAG_RESULT   0x0F
+#define SLEEP_ON                0x10
+#define SLEEP_OFF               0x11
+#define PARTIAL_DISPALY_ON      0x12
+#define NORMAL_DISPALY_ON       0x13
+#define INVERSION_DISPALY_OFF   0x20
+#define INVERSION_DISPALY_ON    0x21
+#define GAMMA_SET               0x26
+#define DISPALY_OFF             0x28
+#define DISPALY_ON              0x29
+#define HORIZONTAL_ADDRESS_SET  0x2A
+#define VERTICAL_ADDRESS_SET    0x2B
+#define MEMORY_WRITE            0x2C
+#define COLOR_SET               0x2D
+#define MEMORY_READ             0x2E
+#define PARTIAL_AREA            0x30
+#define VERTICAL_SCROL_DEFINE   0x33
+#define TEAR_EFFECT_LINE_OFF    0x34
+#define TEAR_EFFECT_LINE_ON     0x35
+#define MEMORY_ACCESS_CTL       0x36
+#define VERTICAL_SCROL_S_ADD    0x37
+#define IDLE_MODE_OFF           0x38
+#define IDLE_MODE_ON            0x39
+#define PIXEL_FORMAT_SET        0x3A
+#define WRITE_MEMORY_CONTINUE   0x3C
+#define READ_MEMORY_CONTINUE    0x3E
+#define SET_TEAR_SCANLINE       0x44
+#define GET_SCANLINE            0x45
+#define WRITE_BRIGHTNESS        0x51
+#define READ_BRIGHTNESS         0x52
+#define WRITE_CTRL_DISPALY      0x53
+#define READ_CTRL_DISPALY       0x54
+#define WRITE_BRIGHTNESS_CTL    0x55
+#define READ_BRIGHTNESS_CTL     0x56
+#define WRITE_MIN_BRIGHTNESS    0x5E
+#define READ_MIN_BRIGHTNESS     0x5F
+#define READ_ID1                0xDA
+#define READ_ID2                0xDB
+#define READ_ID3                0xDC
+#define RGB_IF_SIGNAL_CTL       0xB0
+#define NORMAL_FRAME_CTL        0xB1
+#define IDLE_FRAME_CTL          0xB2
+#define PARTIAL_FRAME_CTL       0xB3
+#define INVERSION_CTL           0xB4
+#define BLANK_PORCH_CTL         0xB5
+#define DISPALY_FUNCTION_CTL    0xB6
+#define ENTRY_MODE_SET          0xB7
+#define BACKLIGHT_CTL1          0xB8
+#define BACKLIGHT_CTL2          0xB9
+#define BACKLIGHT_CTL3          0xBA
+#define BACKLIGHT_CTL4          0xBB
+#define BACKLIGHT_CTL5          0xBC
+#define BACKLIGHT_CTL7          0xBE
+#define BACKLIGHT_CTL8          0xBF
+#define POWER_CTL1              0xC0
+#define POWER_CTL2              0xC1
+#define VCOM_CTL1               0xC5
+#define VCOM_CTL2               0xC7
+#define NV_MEMORY_WRITE         0xD0
+#define NV_MEMORY_PROTECT_KEY   0xD1
+#define NV_MEMORY_STATUS_READ   0xD2
+#define READ_ID4                0xD3
+#define POSITIVE_GAMMA_CORRECT  0xE0
+#define NEGATIVE_GAMMA_CORRECT  0xE1
+#define DIGITAL_GAMMA_CTL1      0xE2
+#define DIGITAL_GAMMA_CTL2      0xE3
+#define INTERFACE_CTL           0xF6
+
+#define DCX_IO                  (33)
+#define DCX_GPIONUM             (2)
+
+#define SPI_CHANNEL             0
+#define SPI_SLAVE_SELECT        3
+/* clang-format on */
+
+void tft_hard_init(void);
+void tft_write_command(uint8_t cmd);
+void tft_write_byte(uint8_t *data_buf, uint32_t length);
+void tft_write_half(uint16_t *data_buf, uint32_t length);
+void tft_write_word(uint32_t *data_buf, uint32_t length, uint32_t flag);
+void tft_fill_data(uint32_t *data_buf, uint32_t length);
+
+#endif
+

+ 26 - 0
lib/firmware/include/ov2640.h

@@ -0,0 +1,26 @@
+/* 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.
+ */
+#ifndef _OV2640_H
+#define _OV2640_H
+
+#include <stdint.h>
+
+#define OV2640_ADDR         0x60
+
+int ov2640_init(void);
+int ov2640_read_id(uint16_t *manuf_id, uint16_t *device_id);
+
+#endif /* _OV2640_H */
+

+ 52 - 0
lib/firmware/include/ov5640.h

@@ -0,0 +1,52 @@
+/* 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.
+ */
+#ifndef _OV5640_H
+#define _OV5640_H
+
+#include <stdint.h>
+
+#define OV5640_ID           0X5640
+#define OV5640_ADDR         0X78
+#define OV5640_CHIPIDH      0X300A
+#define OV5640_CHIPIDL      0X300B
+
+#define XSIZE               320
+#define YSIZE               240
+#define LCD_GRAM_ADDRESS    0x60020000
+
+#define QQVGA_160_120       0
+#define QCIF_176_144        1
+#define QVGA_320_240        2
+#define WQVGA_400_240       3
+#define CIF_352_288         4
+
+#define jpeg_buf_size       (30*1024)
+
+const uint16_t jpeg_size_tbl[][2]=
+{
+    160, 120,   /*QQVGA*/
+    176, 144,   /*QCIF*/
+    320, 240,   /*QVGA*/
+    400, 240,   /*WQVGA*/
+    352, 288,   /*CIF*/
+};
+
+uint8_t ov5640_wr_reg(uint16_t reg, uint8_t data);
+uint8_t ov5640_rd_reg(uint16_t reg);
+uint8_t ov5640_init(void);
+void ov5640_flash_lamp(uint8_t sw);
+
+#endif
+

+ 287 - 0
lib/firmware/include/ov5640cfg.h

@@ -0,0 +1,287 @@
+/* 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.
+ */
+#ifndef _OV5640CFG_H
+#define _OV5640CFG_H
+
+#include "ov5640.h"
+
+const uint16_t ov5640_init_reg_tbl[][2]=
+{
+    /* 24MHz input clock, 24MHz PCLK */
+    0x3008, 0x42, /* software power down, bit[6] */
+    0x3103, 0x03, /* system clock from PLL, bit[1] */
+    0x3017, 0xff, /* FREX, Vsync, HREF, PCLK, D[9:6] output enable */
+    0x3018, 0xff, /* D[5:0], GPIO[1:0] output enable */
+    0x3034, 0x1a, /* MIPI 10-bit*/
+    0x3035, 0x31, /* PLL */
+    0x3036, 0x80, /* PLL */
+    0x3037, 0x13, /* PLL root divider, bit[4], PLL pre-divider, bit[3:0] */
+    0x3108, 0x01, /* PCLK root divider, bit[5:4], SCLK2x root divider, bit[3:2] */
+    /* SCLK root divider, bit[1:0] */
+    0x3630, 0x36,
+    0x3631, 0x0e,
+    0x3632, 0xe2,
+    0x3633, 0x12,
+    0x3621, 0xe0,
+    0x3704, 0xa0,
+    0x3703, 0x5a,
+    0x3715, 0x78,
+    0x3717, 0x01,
+    0x370b, 0x60,
+    0x3705, 0x1a,
+    0x3905, 0x02,
+    0x3906, 0x10,
+    0x3901, 0x0a,
+    0x3731, 0x12,
+    0x3600, 0x08, /* VCM control */
+    0x3601, 0x33, /* VCM control */
+    0x302d, 0x60, /* system control */
+    0x3620, 0x52,
+    0x371b, 0x20,
+    0x471c, 0x50,
+    0x3a13, 0x43, /* pre-gain = 1.047x */
+    0x3a18, 0x00, /* gain ceiling */
+    0x3a19, 0xf8, /* gain ceiling = 15.5x */
+    0x3635, 0x13,
+    0x3636, 0x03,
+    0x3634, 0x40,
+    0x3622, 0x01,
+    /* 50/60Hz detection 50/60Hz */
+    0x3c01, 0x34, /* Band auto, bit[7] */
+    0x3c04, 0x28, /* threshold low sum */
+    0x3c05, 0x98, /* threshold high sum */
+    0x3c06, 0x00, /* light meter 1 threshold[15:8] */
+    0x3c07, 0x07, /* light meter 1 threshold[7:0] */
+    0x3c08, 0x00, /* light meter 2 threshold[15:8] */
+    0x3c09, 0x1c, /* light meter 2 threshold[7:0] */
+    0x3c0a, 0x9c, /* sample number[15:8] */
+    0x3c0b, 0x40, /* sample number[7:0] */
+    0x3810, 0x00, /* Timing Hoffset[11:8] */
+    0x3811, 0x10, /* Timing Hoffset[7:0] */
+    0x3812, 0x00, /* Timing Voffset[10:8] */
+    0x3708, 0x64,
+    0x4001, 0x02, /* BLC start from line 2 */
+    0x4005, 0x1a, /* BLC always update */
+    0x3000, 0x00, /* enable blocks */
+    0x3004, 0xff, /* enable clocks */
+    0x300e, 0x58, /* MIPI power down, DVP enable */
+    0x302e, 0x00,
+    0x4300, 0x61,
+    0X501F, 0x01,
+    0x3820, 0x46, /* flip */
+    0x3821, 0x00, /* mirror */
+    0x3800, 0x00, /* HS */
+    0x3801, 0x00, /* HS */
+    0x3802, 0x00, /* VS */
+    0x3803, 0x00, /* VS */
+    0x3804, 0x0a, /* HW (HE) */
+    0x3805, 0x3f, /* HW (HE) */
+    0x3806, 0x06, /* VH (VE) */
+    0x3807, 0xa9, /* VH (VE) */
+    0x3814, 0x31, /* timing X inc */
+    0x3815, 0x31, /* timing Y inc */
+    0x3808, (320 >> 8), /* DVPHO */
+    0x3809, (320 & 0xff), /* DVPHO */
+    0x380a, (240 >> 8), /* DVPVO */
+    0x380b, (240 & 0xff), /* DVPVO */
+    0x380c, 0x05, /* HTS */
+    0x380d, 0xF8, /* HTS */
+    0x380e, 0x03, /* VTS */
+    0x380f, 0x84, /* VTS */
+    0x3810, 0x00, /* HTS */
+    0x3811, 0x00, /* HTS */
+    0x3812, 0x00, /* VTS */
+    0x3813, 0x00, /* VTS */
+    0x3618, 0x00,
+    0x3612, 0x29,
+    0x3709, 0x52,
+    0x370c, 0x03,
+    0x3a02, 0x02, /* 60Hz max exposure */
+    0x3a03, 0xe0, /* 60Hz max exposure */
+    0x3a14, 0x02, /* 50Hz max exposure */
+    0x3a15, 0xe0, /* 50Hz max exposure */
+    0x4004, 0x02, /* BLC line number */
+    0x3002, 0x1c, /* reset JFIFO, SFIFO, JPG */
+    0x3006, 0xc3, /* disable clock of JPEG2x, JPEG */
+    0x4713, 0x03, /* JPEG mode 3 */
+    0x4407, 0x04, /* Quantization scale */
+    0x460b, 0x37,
+    0x460c, 0x20,
+    0x4837, 0x16, /* MIPI global timing */
+    0x3824, 0x04, /* PCLK manual divider */
+    0x5001, 0xA3, /* SDE on, scale on, UV average off, color matrix on, AWB on */
+    0x3503, 0x00, /* AEC/AGC on */
+    0x440e, 0x00,
+    0x5000, 0xa7, /* Lenc on, raw gamma on, BPC on, WPC on, CIP on */
+    /* AEC target*/
+    0x3a0f, 0x30, /* stable range in high */
+    0x3a10, 0x28, /* stable range in low */
+    0x3a1b, 0x30, /* stable range out high */
+    0x3a1e, 0x26, /* stable range out low */
+    0x3a11, 0x60, /* fast zone high */
+    0x3a1f, 0x14, /* fast zone low */
+    /* Lens correction for */
+    0x5800, 0x23,
+    0x5801, 0x14,
+    0x5802, 0x0f,
+    0x5803, 0x0f,
+    0x5804, 0x12,
+    0x5805, 0x26,
+    0x5806, 0x0c,
+    0x5807, 0x08,
+    0x5808, 0x05,
+    0x5809, 0x05,
+    0x580a, 0x08,
+    0x580b, 0x0d,
+    0x580c, 0x08,
+    0x580d, 0x03,
+    0x580e, 0x00,
+    0x580f, 0x00,
+    0x5810, 0x03,
+    0x5811, 0x09,
+    0x5812, 0x07,
+    0x5813, 0x03,
+    0x5814, 0x00,
+    0x5815, 0x01,
+    0x5816, 0x03,
+    0x5817, 0x08,
+    0x5818, 0x0d,
+    0x5819, 0x08,
+    0x581a, 0x05,
+    0x581b, 0x06,
+    0x581c, 0x08,
+    0x581d, 0x0e,
+    0x581e, 0x29,
+    0x581f, 0x17,
+    0x5820, 0x11,
+    0x5821, 0x11,
+    0x5822, 0x15,
+    0x5823, 0x28,
+    0x5824, 0x46,
+    0x5825, 0x26,
+    0x5826, 0x08,
+    0x5827, 0x26,
+    0x5828, 0x64,
+    0x5829, 0x26,
+    0x582a, 0x24,
+    0x582b, 0x22,
+    0x582c, 0x24,
+    0x582d, 0x24,
+    0x582e, 0x06,
+    0x582f, 0x22,
+    0x5830, 0x40,
+    0x5831, 0x42,
+    0x5832, 0x24,
+    0x5833, 0x26,
+    0x5834, 0x24,
+    0x5835, 0x22,
+    0x5836, 0x22,
+    0x5837, 0x26,
+    0x5838, 0x44,
+    0x5839, 0x24,
+    0x583a, 0x26,
+    0x583b, 0x28,
+    0x583c, 0x42,
+    0x583d, 0xce, /* lenc BR offset */
+    /* AWB */
+    0x5180, 0xff, /* AWB B block */
+    0x5181, 0xf2, /* AWB control */
+    0x5182, 0x00, /* [7:4] max local counter, [3:0] max fast counter */
+    0x5183, 0x14, /* AWB advanced */
+    0x5184, 0x25,
+    0x5185, 0x24,
+    0x5186, 0x09,
+    0x5187, 0x09,
+    0x5188, 0x09,
+    0x5189, 0x75,
+    0x518a, 0x54,
+    0x518b, 0xe0,
+    0x518c, 0xb2,
+    0x518d, 0x42,
+    0x518e, 0x3d,
+    0x518f, 0x56,
+    0x5190, 0x46,
+    0x5191, 0xf8, /* AWB top limit */
+    0x5192, 0x04, /* AWB bottom limit */
+    0x5193, 0x70, /* red limit */
+    0x5194, 0xf0, /* green limit */
+    0x5195, 0xf0, /* blue limit */
+    0x5196, 0x03, /* AWB control*/
+    0x5197, 0x01, /* local limit */
+    0x5198, 0x04,
+    0x5199, 0x12,
+    0x519a, 0x04,
+    0x519b, 0x00,
+    0x519c, 0x06,
+    0x519d, 0x82,
+    0x519e, 0x38, /* AWB control */
+    /* Gamma */
+    0x5480, 0x01, /* Gamma bias plus on, bit[0] */
+    0x5481, 0x08,
+    0x5482, 0x14,
+    0x5483, 0x28,
+    0x5484, 0x51,
+    0x5485, 0x65,
+    0x5486, 0x71,
+    0x5487, 0x7d,
+    0x5488, 0x87,
+    0x5489, 0x91,
+    0x548a, 0x9a,
+    0x548b, 0xaa,
+    0x548c, 0xb8,
+    0x548d, 0xcd,
+    0x548e, 0xdd,
+    0x548f, 0xea,
+    0x5490, 0x1d,
+    /* color matrix */
+    0x5381, 0x1e, /* CMX1 for Y */
+    0x5382, 0x5b, /* CMX2 for Y */
+    0x5383, 0x08, /* CMX3 for Y */
+    0x5384, 0x0a, /* CMX4 for U */
+    0x5385, 0x7e, /* CMX5 for U */
+    0x5386, 0x88, /* CMX6 for U */
+    0x5387, 0x7c, /* CMX7 for V */
+    0x5388, 0x6c, /* CMX8 for V */
+    0x5389, 0x10, /* CMX9 for V */
+    0x538a, 0x01, /* sign[9] */
+    0x538b, 0x98, /* sign[8:1] */
+    /* UV adjust UV */
+    0x5580, 0x06, /* saturation on, bit[1] */
+    0x5583, 0x40,
+    0x5584, 0x10,
+    0x5589, 0x10,
+    0x558a, 0x00,
+    0x558b, 0xf8,
+    0x501d, 0x40, /* enable manual offset of contrast */
+    /* CIP */
+    0x5300, 0x08, /* CIP sharpen MT threshold 1 */
+    0x5301, 0x30, /* CIP sharpen MT threshold 2 */
+    0x5302, 0x10, /* CIP sharpen MT offset 1 */
+    0x5303, 0x00, /* CIP sharpen MT offset 2 */
+    0x5304, 0x08, /* CIP DNS threshold 1 */
+    0x5305, 0x30, /* CIP DNS threshold 2 */
+    0x5306, 0x08, /* CIP DNS offset 1 */
+    0x5307, 0x16, /* CIP DNS offset 2 */
+    0x5309, 0x08, /* CIP sharpen TH threshold 1 */
+    0x530a, 0x30, /* CIP sharpen TH threshold 2 */
+    0x530b, 0x04, /* CIP sharpen TH offset 1 */
+    0x530c, 0x06, /* CIP sharpen TH offset 2 */
+    0x5025, 0x00,
+    0x3008, 0x02, /* wake up from standby, bit[6] */
+    0x4740, 0X21, /*VSYNC active HIGH */
+};
+
+#endif
+

+ 47 - 0
lib/firmware/include/sd3068.h

@@ -0,0 +1,47 @@
+/* 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.
+ */
+#ifndef _SD3068_H
+#define _SD3068_H
+
+#include <stdint.h>
+
+#define SD3068_ADDR         0x32
+#define SD3068_ADDR_LENTH   7
+
+struct time_t
+{
+    uint32_t year:6;
+    uint32_t month:4;
+    uint32_t day:5;
+    uint32_t hour:5;
+    uint32_t min:6;
+    uint32_t sec:6;
+} __attribute__((packed, aligned(4)));
+
+void sd3068_init(uint8_t sel);
+int sd3068_write_enable(void);
+int sd3068_write_disable(void);
+int sd3068_set_time(struct time_t time);
+int sd3068_get_time(struct time_t *time);
+int sd3068_write_data(uint8_t addr, uint8_t *data_buf, uint8_t length);
+int sd3068_read_data(uint8_t addr, uint8_t *data_buf, uint8_t length);
+int sd3068_set_time_dma(struct time_t time);
+int sd3068_write_enable_dma(void);
+int sd3068_get_time_dma(struct time_t *time);
+int sd3068_read_data_dma(uint8_t addr, uint8_t *data_buf, uint8_t length);
+int sd3068_write_data_dma(uint8_t addr, uint8_t *data_buf, uint8_t length);
+
+#endif
+

+ 113 - 0
lib/firmware/include/w25qxx.h

@@ -0,0 +1,113 @@
+/* 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.
+ */
+#ifndef _W25QXX_H
+#define _W25QXX_H
+
+#include <stdint.h>
+
+/* clang-format off */
+#define DATALENGTH                          8
+
+#define SPI_SLAVE_SELECT                    (0x01)
+
+#define w25qxx_FLASH_PAGE_SIZE              256
+#define w25qxx_FLASH_SECTOR_SIZE            4096
+#define w25qxx_FLASH_PAGE_NUM_PER_SECTOR    16
+#define w25qxx_FLASH_CHIP_SIZE              (16777216 UL)
+
+#define WRITE_ENABLE                        0x06
+#define WRITE_DISABLE                       0x04
+#define READ_REG1                           0x05
+#define READ_REG2                           0x35
+#define READ_REG3                           0x15
+#define WRITE_REG1                          0x01
+#define WRITE_REG2                          0x31
+#define WRITE_REG3                          0x11
+#define READ_DATA                           0x03
+#define FAST_READ                           0x0B
+#define FAST_READ_DUAL_OUTPUT               0x3B
+#define FAST_READ_QUAL_OUTPUT               0x6B
+#define FAST_READ_DUAL_IO                   0xBB
+#define FAST_READ_QUAL_IO                   0xEB
+#define DUAL_READ_RESET                     0xFFFF
+#define QUAL_READ_RESET                     0xFF
+#define PAGE_PROGRAM                        0x02
+#define QUAD_PAGE_PROGRAM                   0x32
+#define SECTOR_ERASE                        0x20
+#define BLOCK_32K_ERASE                     0x52
+#define BLOCK_64K_ERASE                     0xD8
+#define CHIP_ERASE                          0x60
+#define READ_ID                             0x90
+#define ENABLE_QPI                          0x38
+#define EXIT_QPI                            0xFF
+#define ENABLE_RESET                        0x66
+#define RESET_DEVICE                        0x99
+
+#define REG1_BUSY_MASK                      0x01
+#define REG2_QUAL_MASK                      0x02
+
+#define LETOBE(x)     ((x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24))
+/* clang-format on */
+
+/**
+ * @brief      w25qxx operating status enumerate
+ */
+enum w25qxx_status_t
+{
+    W25QXX_OK = 0,
+    W25QXX_BUSY,
+    W25QXX_ERROR,
+};
+
+/**
+ * @brief      w25qxx read operating enumerate
+ */
+enum w25qxx_read_t
+{
+    W25QXX_STANDARD = 0,
+    W25QXX_STANDARD_FAST,
+    W25QXX_DUAL,
+    W25QXX_DUAL_FAST,
+    W25QXX_QUAD,
+    W25QXX_QUAD_FAST,
+};
+
+enum w25qxx_status_t w25qxx_init(uint8_t spi_index, uint8_t spi_ss);
+enum w25qxx_status_t w25qxx_is_busy(void);
+enum w25qxx_status_t w25qxx_chip_erase(void);
+enum w25qxx_status_t w25qxx_enable_quad_mode(void);
+enum w25qxx_status_t w25qxx_disable_quad_mode(void);
+enum w25qxx_status_t w25qxx_sector_erase(uint32_t addr);
+enum w25qxx_status_t w25qxx_32k_block_erase(uint32_t addr);
+enum w25qxx_status_t w25qxx_64k_block_erase(uint32_t addr);
+enum w25qxx_status_t w25qxx_read_status_reg1(uint8_t *reg_data);
+enum w25qxx_status_t w25qxx_read_status_reg2(uint8_t *reg_data);
+enum w25qxx_status_t w25qxx_write_status_reg(uint8_t reg1_data, uint8_t reg2_data);
+enum w25qxx_status_t w25qxx_read_id(uint8_t *manuf_id, uint8_t *device_id);
+enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t *data_buf, uint32_t length);
+enum w25qxx_status_t w25qxx_write_data_direct(uint32_t addr, uint8_t *data_buf, uint32_t length);
+enum w25qxx_status_t w25qxx_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode);
+enum w25qxx_status_t w25qxx_enable_xip_mode(void);
+enum w25qxx_status_t w25qxx_disable_xip_mode(void);
+enum w25qxx_status_t w25qxx_read_id_dma(uint8_t *manuf_id, uint8_t *device_id);
+enum w25qxx_status_t w25qxx_sector_erase_dma(uint32_t addr);
+enum w25qxx_status_t w25qxx_init_dma(uint8_t spi_index, uint8_t spi_ss);
+enum w25qxx_status_t w25qxx_write_data_direct_dma(uint32_t addr, uint8_t *data_buf, uint32_t length);
+enum w25qxx_status_t w25qxx_read_data_dma(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode);
+enum w25qxx_status_t w25qxx_is_busy_dma(void);
+enum w25qxx_status_t w25qxx_enable_quad_mode_dma(void);
+
+#endif
+

+ 210 - 0
lib/firmware/lcd.c

@@ -0,0 +1,210 @@
+/* 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.
+ */
+#include <string.h>
+#include "lcd.h"
+#include "nt35310.h"
+#include "font.h"
+#include "common.h"
+#include "sleep.h"
+
+static lcd_ctl_t lcd_ctl;
+
+void lcd_polling_enable(void)
+{
+    lcd_ctl.mode = 0;
+}
+
+void lcd_interrupt_enable(void)
+{
+    lcd_ctl.mode = 1;
+
+}
+
+void lcd_init(void)
+{
+    uint8_t data = 0;
+
+    tft_hard_init();
+    /*soft reset*/
+    tft_write_command(SOFTWARE_RESET);
+    msleep(100);
+    /*exit sleep*/
+    tft_write_command(SLEEP_OFF);
+    msleep(100);
+    /*pixel format*/
+    tft_write_command(PIXEL_FORMAT_SET);
+    data = 0x55;
+    tft_write_byte(&data, 1);
+    lcd_set_direction(DIR_XY_RLUD);
+    /*display on*/
+    tft_write_command(DISPALY_ON);
+    lcd_polling_enable();
+}
+
+void lcd_set_direction(enum lcd_dir_t dir)
+{
+    lcd_ctl.dir = dir;
+    if (dir & DIR_XY_MASK)
+    {
+        lcd_ctl.width = LCD_Y_MAX - 1;
+        lcd_ctl.height = LCD_X_MAX - 1;
+    }
+    else
+    {
+        lcd_ctl.width = LCD_X_MAX - 1;
+        lcd_ctl.height = LCD_Y_MAX - 1;
+    }
+
+    tft_write_command(MEMORY_ACCESS_CTL);
+    tft_write_byte((uint8_t *)&dir, 1);
+}
+
+void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
+{
+    uint8_t data[4] = {0};
+
+    data[0] = (uint8_t)(x1 >> 8);
+    data[1] = (uint8_t)(x1);
+    data[2] = (uint8_t)(x2 >> 8);
+    data[3] = (uint8_t)(x2);
+    tft_write_command(HORIZONTAL_ADDRESS_SET);
+    tft_write_byte(data, 4);
+
+    data[0] = (uint8_t)(y1 >> 8);
+    data[1] = (uint8_t)(y1);
+    data[2] = (uint8_t)(y2 >> 8);
+    data[3] = (uint8_t)(y2);
+    tft_write_command(VERTICAL_ADDRESS_SET);
+    tft_write_byte(data, 4);
+
+    tft_write_command(MEMORY_WRITE);
+}
+
+void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
+{
+    lcd_set_area(x, y, x, y);
+    tft_write_half(&color, 1);
+}
+
+void lcd_draw_char(uint16_t x, uint16_t y, char c, uint16_t color)
+{
+    uint8_t i = 0;
+    uint8_t j = 0;
+    uint8_t data = 0;
+
+    for (i = 0; i < 16; i++)
+    {
+        data = ascii0816[c * 16 + i];
+        for (j = 0; j < 8; j++)
+        {
+            if (data & 0x80)
+                lcd_draw_point(x + j, y, color);
+            data <<= 1;
+        }
+        y++;
+    }
+}
+
+void lcd_draw_string(uint16_t x, uint16_t y, char *str, uint16_t color)
+{
+    while (*str)
+    {
+        lcd_draw_char(x, y, *str, color);
+        str++;
+        x += 8;
+    }
+}
+
+void lcd_ram_draw_string(char *str, uint32_t *ptr, uint16_t font_color, uint16_t bg_color)
+{
+    uint8_t i = 0;
+    uint8_t j = 0;
+    uint8_t data = 0;
+    uint8_t *pdata = NULL;
+    uint16_t width = 0;
+    uint32_t *pixel = NULL;
+
+    width = 4 * strlen(str);
+    while (*str)
+    {
+        pdata = (uint8_t *)&ascii0816[(*str) * 16];
+        for (i = 0; i < 16; i++)
+        {
+            data = *pdata++;
+            pixel = ptr + i * width;
+            for (j = 0; j < 4; j++)
+            {
+                switch (data >> 6)
+                {
+                    case 0:
+                        *pixel = ((uint32_t)bg_color << 16) | bg_color;
+                        break;
+                    case 1:
+                        *pixel = ((uint32_t)bg_color << 16) | font_color;
+                        break;
+                    case 2:
+                        *pixel = ((uint32_t)font_color << 16) | bg_color;
+                        break;
+                    case 3:
+                        *pixel = ((uint32_t)font_color << 16) | font_color;
+                        break;
+                    default:
+                        *pixel = 0;
+                        break;
+                }
+                data <<= 2;
+                pixel++;
+            }
+        }
+        str++;
+        ptr += 4;
+    }
+}
+
+void lcd_clear(uint16_t color)
+{
+    uint32_t data = ((uint32_t)color << 16) | (uint32_t)color;
+
+    lcd_set_area(0, 0, lcd_ctl.width, lcd_ctl.height);
+    tft_fill_data(&data, LCD_X_MAX * LCD_Y_MAX / 2);
+}
+
+void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color)
+{
+    uint32_t data_buf[640] = {0};
+    uint32_t *p = data_buf;
+    uint32_t data = color;
+    uint32_t index = 0;
+
+    data = (data << 16) | data;
+    for (index = 0; index < 160 * width; index++)
+        *p++ = data;
+
+    lcd_set_area(x1, y1, x2, y1 + width - 1);
+    tft_write_word(data_buf, ((x2 - x1 + 1) * width + 1) / 2, 0);
+    lcd_set_area(x1, y2 - width + 1, x2, y2);
+    tft_write_word(data_buf, ((x2 - x1 + 1) * width + 1) / 2, 0);
+    lcd_set_area(x1, y1, x1 + width - 1, y2);
+    tft_write_word(data_buf, ((y2 - y1 + 1) * width + 1) / 2, 0);
+    lcd_set_area(x2 - width + 1, y1, x2, y2);
+    tft_write_word(data_buf, ((y2 - y1 + 1) * width + 1) / 2, 0);
+}
+
+void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr)
+{
+    lcd_set_area(x1, y1, x1 + width - 1, y1 + height - 1);
+    tft_write_word(ptr, width * height / 2, lcd_ctl.mode ? 2 : 0);
+}
+

+ 115 - 0
lib/firmware/nt35310.c

@@ -0,0 +1,115 @@
+/* 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.
+ */
+#include "nt35310.h"
+#include "sysctl.h"
+#include "fpioa.h"
+#include "gpiohs.h"
+#include "spi.h"
+#include "dmac.h"
+#include "plic.h"
+#include <common.h>
+
+#define __SPI_SYSCTL(x, y)  SYSCTL_##x##_SPI##y
+#define _SPI_SYSCTL(x, y)   __SPI_SYSCTL(x, y)
+#define SPI_SYSCTL(x)       _SPI_SYSCTL(x, SPI_CHANNEL)
+#define __SPI_SS(x, y)      FUNC_SPI##x##_SS##y
+#define _SPI_SS(x, y)       __SPI_SS(x, y)
+#define SPI_SS              _SPI_SS(SPI_CHANNEL, SPI_SLAVE_SELECT)
+#define __SPI(x, y)         FUNC_SPI##x##_##y
+#define _SPI(x, y)          __SPI(x, y)
+#define SPI(x)              _SPI(SPI_CHANNEL, x)
+
+void  init_dcx(void)
+{
+    gpiohs_init();
+    fpioa_set_function(DCX_IO, FUNC_GPIOHS0 + DCX_GPIONUM);/*dcx*/
+    gpiohs_set_drive_mode(DCX_GPIONUM, GPIO_DM_Output);
+    gpiohs_set_pin_value(DCX_GPIONUM, GPIO_PV_High);
+}
+
+void set_dcx_control(void)
+{
+    gpiohs_set_pin_value(DCX_GPIONUM, GPIO_PV_Low);
+}
+
+void set_dcx_data(void)
+{
+    gpiohs_set_pin_value(DCX_GPIONUM, GPIO_PV_High);
+}
+
+void pin_mux_init(void)
+{
+    fpioa_set_function(31, SPI_SS);
+    fpioa_set_function(32, SPI(SCLK));
+    sysctl->misc.reserved0 = 1;
+}
+
+void tft_hard_init(void)
+{
+    init_dcx();
+    pin_mux_init();
+    spi_master_config(SPI_CHANNEL, SPI_MODE_2, SPI_FF_OCTAL, 8);
+}
+
+void tft_write_command(uint8_t cmd)
+{
+    set_dcx_control();
+    spi_set_tmod(SPI_CHANNEL, SPI_TMOD_TRANS);
+    spi_set_frame_format(SPI_CHANNEL, SPI_FF_OCTAL);
+    spi_set_frame_size(SPI_CHANNEL, 8);
+    spi_trans_config(SPI_CHANNEL, 8/*instrction length*/, 0/*address length*/, 0/*wait cycles*/, SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
+    spi_normal_send_dma(DMAC_CHANNEL0, SPI_CHANNEL, 1 << SPI_SLAVE_SELECT, (uint8_t *)(&cmd), 1,SPI_TRANS_CHAR);
+}
+
+void tft_write_byte(uint8_t *data_buf, uint32_t length)
+{
+    set_dcx_data();
+    spi_set_tmod(SPI_CHANNEL, SPI_TMOD_TRANS);
+    spi_set_frame_format(SPI_CHANNEL, SPI_FF_OCTAL);
+    spi_set_frame_size(SPI_CHANNEL, 8);
+    spi_trans_config(SPI_CHANNEL, 8/*instrction length*/, 0/*address length*/, 0/*wait cycles*/, SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
+    spi_normal_send_dma(DMAC_CHANNEL0, SPI_CHANNEL, 1 << SPI_SLAVE_SELECT, data_buf, length, SPI_TRANS_CHAR);
+}
+
+void tft_write_half(uint16_t *data_buf, uint32_t length)
+{
+    set_dcx_data();
+    spi_set_tmod(SPI_CHANNEL, SPI_TMOD_TRANS);
+    spi_set_frame_format(SPI_CHANNEL, SPI_FF_OCTAL);
+    spi_set_frame_size(SPI_CHANNEL, 16);
+    spi_trans_config(SPI_CHANNEL, 16/*instrction length*/, 0/*address length*/, 0/*wait cycles*/, SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
+    spi_normal_send_dma(DMAC_CHANNEL0, SPI_CHANNEL, 1 << SPI_SLAVE_SELECT,data_buf, length, SPI_TRANS_SHORT);
+}
+
+void tft_write_word(uint32_t *data_buf, uint32_t length, uint32_t flag)
+{
+    set_dcx_data();
+    spi_set_tmod(SPI_CHANNEL, SPI_TMOD_TRANS);
+    spi_set_frame_format(SPI_CHANNEL, SPI_FF_OCTAL);
+    spi_set_frame_size(SPI_CHANNEL, 32);
+    spi_trans_config(SPI_CHANNEL, 0/*instrction length*/, 32/*address length*/, 0/*wait cycles*/, SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
+    spi_normal_send_dma(DMAC_CHANNEL0, SPI_CHANNEL, 1 << SPI_SLAVE_SELECT,data_buf, length, SPI_TRANS_INT);
+}
+
+void tft_fill_data(uint32_t *data_buf, uint32_t length)
+{
+    set_dcx_data();
+    spi_set_tmod(SPI_CHANNEL, SPI_TMOD_TRANS);
+    spi_set_frame_format(SPI_CHANNEL, SPI_FF_OCTAL);
+    spi_set_frame_size(SPI_CHANNEL, 32);
+    spi_trans_config(SPI_CHANNEL, 0/*instrction length*/, 32/*address length*/, 0/*wait cycles*/, SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
+    spi_fill_dma(DMAC_CHANNEL0, SPI_CHANNEL, 1 << SPI_SLAVE_SELECT,data_buf, length);
+}
+

+ 243 - 0
lib/firmware/ov2640.c

@@ -0,0 +1,243 @@
+/* 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.
+ */
+#include <stdio.h>
+#include "ov2640.h"
+#include "dvp.h"
+#include "plic.h"
+
+/* QVGA Window Size */
+static const uint8_t ov2640_config[][2] =
+{
+    {0xff, 0x00},
+    {0x2c, 0xff},
+    {0x2e, 0xdf},
+    {0xff, 0x01},
+    {0x3c, 0x32},
+    {0x11, 0x00},
+    {0x09, 0x00},
+    {0x04, 0x28},
+    {0x13, 0xe5},
+    {0x14, 0xa8},
+    {0x15, 0x00},
+    {0x2c, 0x0c},
+    {0x33, 0x78},
+    {0x3a, 0x33},
+    {0x3b, 0xfb},
+    {0x3e, 0x00},
+    {0x43, 0x11},
+    {0x16, 0x10},
+    {0x39, 0x92},
+    {0x35, 0xda},
+    {0x22, 0x1a},
+    {0x23, 0x00},
+    {0x34, 0xc0},
+    {0x06, 0x88},
+    {0x07, 0xc0},
+    {0x0d, 0x87},
+    {0x0e, 0x41},
+    {0x4c, 0x00},
+    {0x48, 0x00},
+    {0x5b, 0x00},
+    {0x42, 0x03},
+    {0x4a, 0x81},
+    {0x21, 0x99},
+    {0x24, 0x40},
+    {0x25, 0x38},
+    {0x26, 0x82},
+    {0x5c, 0x00},
+    {0x63, 0x00},
+    {0x61, 0x70},
+    {0x62, 0x80},
+    {0x7c, 0x05},
+    {0x20, 0x80},
+    {0x28, 0x30},
+    {0x6c, 0x00},
+    {0x6d, 0x80},
+    {0x6e, 0x00},
+    {0x70, 0x02},
+    {0x71, 0x94},
+    {0x73, 0xc1},
+    {0x0c, 0x3c},
+    {0x5d, 0x55},
+    {0x5e, 0x7d},
+    {0x5f, 0x7d},
+    {0x60, 0x55},
+    {0x12, 0x40},
+    {0x32, 0x09},
+    {0x17, 0x11},
+    {0x18, 0x43},
+    {0x19, 0x00},
+    {0x1a, 0x97},
+    {0x32, 0x09},
+    {0x37, 0x42},
+    {0x4f, 0xbb},
+    {0x50, 0x9c},
+    {0x6d, 0x80},
+    {0x35, 0x88},
+    {0x22, 0x0a},
+    {0x6d, 0x80},
+    {0x3d, 0xe1},
+    {0xff, 0x00},
+    {0xe5, 0x7f},
+    {0xf9, 0xc0},
+    {0x41, 0x24},
+    {0x44, 0x06},
+    {0xe0, 0x14},
+    {0x76, 0xff},
+    {0x33, 0xa0},
+    {0x42, 0x20},
+    {0x43, 0x18},
+    {0x4c, 0x00},
+    {0x87, 0xd0},
+    {0x88, 0x3f},
+    {0xd7, 0x03},
+    {0xd9, 0x10},
+    {0xd3, 0x82},
+    {0xc8, 0x08},
+    {0xc9, 0x80},
+    {0x7c, 0x00},
+    {0x7d, 0x00},
+    {0x7c, 0x03},
+    {0x7d, 0x48},
+    {0x7d, 0x48},
+    {0x7c, 0x08},
+    {0x7d, 0x20},
+    {0x7d, 0x10},
+    {0x7d, 0x0e},
+    {0x90, 0x00},
+    {0x91, 0x0e},
+    {0x91, 0x1a},
+    {0x91, 0x31},
+    {0x91, 0x5a},
+    {0x91, 0x69},
+    {0x91, 0x75},
+    {0x91, 0x7e},
+    {0x91, 0x88},
+    {0x91, 0x8f},
+    {0x91, 0x96},
+    {0x91, 0xa3},
+    {0x91, 0xaf},
+    {0x91, 0xc4},
+    {0x91, 0xd7},
+    {0x91, 0xe8},
+    {0x91, 0x20},
+    {0x92, 0x00},
+    {0x93, 0x06},
+    {0x93, 0xe3},
+    {0x93, 0x03},
+    {0x93, 0x03},
+    {0x93, 0x00},
+    {0x93, 0x02},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x93, 0x00},
+    {0x96, 0x00},
+    {0x97, 0x08},
+    {0x97, 0x19},
+    {0x97, 0x02},
+    {0x97, 0x0c},
+    {0x97, 0x24},
+    {0x97, 0x30},
+    {0x97, 0x28},
+    {0x97, 0x26},
+    {0x97, 0x02},
+    {0x97, 0x98},
+    {0x97, 0x80},
+    {0x97, 0x00},
+    {0x97, 0x00},
+    {0xa4, 0x00},
+    {0xa8, 0x00},
+    {0xc5, 0x11},
+    {0xc6, 0x51},
+    {0xbf, 0x80},
+    {0xc7, 0x10},
+    {0xb6, 0x66},
+    {0xb8, 0xa5},
+    {0xb7, 0x64},
+    {0xb9, 0x7c},
+    {0xb3, 0xaf},
+    {0xb4, 0x97},
+    {0xb5, 0xff},
+    {0xb0, 0xc5},
+    {0xb1, 0x94},
+    {0xb2, 0x0f},
+    {0xc4, 0x5c},
+    {0xa6, 0x00},
+    {0xa7, 0x20},
+    {0xa7, 0xd8},
+    {0xa7, 0x1b},
+    {0xa7, 0x31},
+    {0xa7, 0x00},
+    {0xa7, 0x18},
+    {0xa7, 0x20},
+    {0xa7, 0xd8},
+    {0xa7, 0x19},
+    {0xa7, 0x31},
+    {0xa7, 0x00},
+    {0xa7, 0x18},
+    {0xa7, 0x20},
+    {0xa7, 0xd8},
+    {0xa7, 0x19},
+    {0xa7, 0x31},
+    {0xa7, 0x00},
+    {0xa7, 0x18},
+    {0xe0, 0x04},
+    {0xc0, 0x64},
+    {0xc1, 0x4b},
+    {0x86, 0x3d},
+    {0x50, 0x80},
+    {0x51, 0xc8},
+    {0x52, 0x96},
+    {0x53, 0x00},
+    {0x54, 0x00},
+    {0x55, 0x00},
+    {0x57, 0x00},
+    {0x5a, 0x50},
+    {0x5b, 0x3c},
+    {0x5c, 0x00},
+    {0xd3, 0x04},
+    {0xe0, 0x00},
+    {0xc3, 0xef},
+    {0x7f, 0x00},
+    {0xda, 0x08},
+    {0xe5, 0x1f},
+    {0xe1, 0x67},
+    {0xdd, 0x7f},
+    {0x05, 0x00},
+    {0x98, 0x00},
+    {0x99, 0x00},
+    {0x00, 0x00},
+};
+
+int ov2640_init(void)
+{
+    uint16_t index = 0;
+    for (index = 0; ov2640_config[index][0]; index++)
+        dvp_sccb_write(OV2640_ADDR, ov2640_config[index][0], ov2640_config[index][1]);
+    return 0;
+}
+
+int ov2640_read_id(uint16_t *manuf_id, uint16_t *device_id)
+{
+    dvp_sccb_write(OV2640_ADDR, 0xFF, 0x01);
+    *manuf_id = (dvp_sccb_read(OV2640_ADDR, 0x1C) << 8) | dvp_sccb_read(OV2640_ADDR, 0x1D);
+    *device_id = (dvp_sccb_read(OV2640_ADDR, 0x0A) << 8) | dvp_sccb_read(OV2640_ADDR, 0x0B);
+    return 0;
+}
+

+ 82 - 0
lib/firmware/ov5640.c

@@ -0,0 +1,82 @@
+/* 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.
+ */
+#include "ov5640.h"
+#include "ov5640cfg.h"
+#include <stdio.h>
+#include "ov2640.h"
+#include "dvp.h"
+#include "plic.h"
+
+extern void mdelay(uint32_t ms);
+
+void hal_delay(uint32_t delay)
+{
+    mdelay(delay);
+}
+
+uint8_t ov5640_wr_reg(uint16_t reg,uint8_t data)
+{
+    dvp_sccb_write(OV5640_ADDR, reg, data);
+    return 0;
+}
+
+uint8_t ov5640_rd_reg(uint16_t reg)
+{
+    return dvp_sccb_read(OV5640_ADDR, reg);
+}
+
+uint8_t ov5640_init(void)
+{
+    uint16_t i = 0;
+    uint16_t reg = 0;
+
+    reg = ov5640_rd_reg(OV5640_CHIPIDH);
+    reg <<= 8;
+    reg |= ov5640_rd_reg(OV5640_CHIPIDL);
+    printf("ID: %X \r\n", reg);
+    if(reg != OV5640_ID)
+    {
+        printf("ID: %d \r\n", reg);
+        return 1;
+    }
+
+    ov5640_wr_reg(0x3103,0X11); /*system clock from pad, bit[1]*/
+    ov5640_wr_reg(0X3008,0X82);
+    hal_delay(10);
+
+    for(i = 0; i<sizeof(ov5640_init_reg_tbl) / 4; i++)
+    {
+        ov5640_wr_reg(ov5640_init_reg_tbl[i][0], ov5640_init_reg_tbl[i][1]);
+    }
+
+    hal_delay(50);
+    /* Test for flash light*/
+    ov5640_flash_lamp(1);
+    hal_delay(50);
+    ov5640_flash_lamp(0);
+
+    return 0x00;
+}
+
+void ov5640_flash_lamp(uint8_t sw)
+{
+    ov5640_wr_reg(0x3016, 0X02);
+    ov5640_wr_reg(0x301C, 0X02);
+    if(sw)
+        ov5640_wr_reg(0X3019, 0X02);
+    else
+        ov5640_wr_reg(0X3019, 0X00);
+}
+

+ 195 - 0
lib/firmware/sd3068.c

@@ -0,0 +1,195 @@
+/* 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.
+ */
+#include <stdio.h>
+#include "sd3068.h"
+#include "fpioa.h"
+#include "common.h"
+#include "sysctl.h"
+#include "i2c.h"
+
+uint8_t i2c_bus_no = 0;
+
+void sd3068_init(uint8_t sel)
+{
+    i2c_bus_no = sel;
+}
+
+static int sd3068_write_reg(uint8_t reg, uint8_t *data_buf, uint8_t length)
+{
+    i2c_write_reg(i2c_bus_no, reg, data_buf, length);
+    return 0;
+}
+
+static int sd3068_write_reg_dma(uint8_t reg, uint8_t *data_buf, uint8_t length)
+{
+    i2c_write_reg_dma(DMAC_CHANNEL0, i2c_bus_no, reg, data_buf, length);
+    return 0;
+}
+
+static int sd3068_read_reg(uint8_t reg, uint8_t *data_buf, uint8_t length)
+{
+    i2c_read_reg(i2c_bus_no, reg, data_buf, length);
+    return 0;
+}
+
+static int sd3068_read_reg_dma(uint8_t reg, uint8_t *data_buf, uint8_t length)
+{
+    i2c_read_reg_dma(DMAC_CHANNEL0, DMAC_CHANNEL1, i2c_bus_no, reg, data_buf, length);
+    return 0;
+}
+
+static uint8_t hex2bcd(uint8_t data)
+{
+    return data / 10 * 16 + data % 10;
+}
+
+static uint8_t bcd2hex(uint8_t data)
+{
+    return data / 16 * 10 + data % 16;
+}
+
+int sd3068_write_enable(void)
+{
+    uint8_t data[2] = {0};
+
+    data[0] = 0xFF;
+    data[1] = 0x80;
+    sd3068_write_reg(0x10, &data[1], 1);
+    sd3068_write_reg(0x0F, &data[0], 1);
+
+    return 0;
+}
+
+int sd3068_write_enable_dma(void)
+{
+    uint8_t data[2] = {0};
+
+    data[0] = 0xFF;
+    data[1] = 0x80;
+    sd3068_write_reg_dma(0x10, &data[1], 1);
+    sd3068_write_reg_dma(0x0F, &data[0], 1);
+
+    return 0;
+}
+
+int sd3068_write_disable(void)
+{
+    uint8_t data[2] = {0};
+
+    data[0] = 0x7B;
+    data[1] = 0;
+    sd3068_write_reg(0x0F, data, 2);
+
+    return 0;
+}
+
+int sd3068_write_data(uint8_t addr, uint8_t *data_buf, uint8_t length)
+{
+    addr = ((addr <= 69) ? addr : 69);
+    length = ((length <= 70 - addr) ? length : 70 - addr);
+    sd3068_write_reg(0x2C + addr, data_buf, length);
+
+    return 0;
+}
+
+int sd3068_write_data_dma(uint8_t addr, uint8_t *data_buf, uint8_t length)
+{
+    addr = ((addr <= 69) ? addr : 69);
+    length = ((length <= 70 - addr) ? length : 70 - addr);
+    sd3068_write_reg_dma(0x2C + addr, data_buf, length);
+
+    return 0;
+}
+
+int sd3068_read_data(uint8_t addr, uint8_t *data_buf, uint8_t length)
+{
+    addr = ((addr <= 69) ? addr : 69);
+    length = ((length <= 70 - addr) ? length : 70 - addr);
+    sd3068_read_reg(0x2C + addr, data_buf, length);
+
+    return 0;
+}
+
+int sd3068_read_data_dma(uint8_t addr, uint8_t *data_buf, uint8_t length)
+{
+    addr = ((addr <= 69) ? addr : 69);
+    length = length <= 70 - addr ? length : 70 - addr;
+    sd3068_read_reg_dma(0x2C + addr, data_buf, length);
+
+    return 0;
+}
+
+int sd3068_set_time(struct time_t time)
+{
+    uint8_t data[7] = {0};
+
+    data[0] = hex2bcd(time.sec);
+    data[1] = hex2bcd(time.min);
+    data[2] = hex2bcd(time.hour) | 0x80;
+    data[3] = hex2bcd(5);
+    data[4] = hex2bcd(time.day);
+    data[5] = hex2bcd(time.month);
+    data[6] = hex2bcd(time.year);
+    sd3068_write_reg(0x00, data, 7);
+
+    return 0;
+}
+
+int sd3068_set_time_dma(struct time_t time)
+{
+    uint8_t data[7] = {0};
+
+    data[0] = hex2bcd(time.sec);
+    data[1] = hex2bcd(time.min);
+    data[2] = hex2bcd(time.hour) | 0x80;
+    data[3] = hex2bcd(5);
+    data[4] = hex2bcd(time.day);
+    data[5] = hex2bcd(time.month);
+    data[6] = hex2bcd(time.year);
+    sd3068_write_reg_dma(0x00, data, 7);
+
+    return 0;
+}
+
+int sd3068_get_time(struct time_t *time)
+{
+    uint8_t data[7] = {0};
+
+    sd3068_read_reg(0x00, data, 7);
+    time->sec = bcd2hex(data[0]);
+    time->min = bcd2hex(data[1]);
+    time->hour = bcd2hex(data[2] & 0x7F);
+    time->day = bcd2hex(data[4]);
+    time->month = bcd2hex(data[5]);
+    time->year = bcd2hex(data[6]);
+
+    return 0;
+}
+
+int sd3068_get_time_dma(struct time_t *time)
+{
+    uint8_t data[7] = {0};
+
+    sd3068_read_reg_dma(0x00, data, 7);
+    time->sec = bcd2hex(data[0]);
+    time->min = bcd2hex(data[1]);
+    time->hour = bcd2hex(data[2] & 0x7F);
+    time->day = bcd2hex(data[4]);
+    time->month = bcd2hex(data[5]);
+    time->year = bcd2hex(data[6]);
+
+    return 0;
+}
+

+ 660 - 0
lib/firmware/w25qxx.c

@@ -0,0 +1,660 @@
+/* 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.
+ */
+#include "w25qxx.h"
+#include "fpioa.h"
+#include "spi.h"
+#include "sysctl.h"
+#include "dmac.h"
+
+uint8_t spi_bus_no = 0;
+uint8_t spi_chip_select = 0;
+static volatile struct spi_t *spi_handle;
+
+enum w25qxx_status_t (*w25qxx_page_program_fun)(uint32_t addr, uint8_t *data_buf, uint32_t length);
+enum w25qxx_status_t (*w25qxx_read_fun)(uint32_t addr, uint8_t *data_buf, uint32_t length);
+static enum w25qxx_status_t w25qxx_stand_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length);
+static enum w25qxx_status_t w25qxx_quad_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length);
+static enum w25qxx_status_t w25qxx_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length);
+static enum w25qxx_status_t w25qxx_quad_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length);
+static enum w25qxx_status_t w25qxx_page_program_dma(uint32_t addr, uint8_t *data_buf, uint32_t length);
+static enum w25qxx_status_t w25qxx_quad_page_program_dma(uint32_t addr, uint8_t *data_buf, uint32_t length);
+
+static enum w25qxx_status_t w25qxx_receive_data(uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len)
+{
+    spi_set_tmod(spi_bus_no, SPI_TMOD_EEROM);
+    spi_receive_data(spi_bus_no, spi_chip_select, cmd_buff, cmd_len, rx_buff, rx_len);
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_receive_data_dma(uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len)
+{
+    spi_set_tmod(spi_bus_no, SPI_TMOD_EEROM);
+    spi_receive_data_dma(DMAC_CHANNEL0, DMAC_CHANNEL1, spi_bus_no, spi_chip_select, cmd_buff, cmd_len, rx_buff, rx_len);
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_send_data(uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len)
+{
+    spi_set_tmod(spi_bus_no, SPI_TMOD_TRANS);
+    spi_send_data(spi_bus_no, spi_chip_select, cmd_buff, cmd_len, tx_buff, tx_len);
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_send_data_dma(uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len)
+{
+    spi_set_tmod(spi_bus_no, SPI_TMOD_TRANS);
+    spi_send_data_dma(DMAC_CHANNEL0, spi_bus_no, spi_chip_select, cmd_buff, cmd_len, tx_buff, tx_len);
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_receive_data_enhanced(uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len)
+{
+    spi_special_receive_data(spi_bus_no, spi_chip_select, cmd_buff, cmd_len, rx_buff, rx_len);
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_receive_data_enhanced_dma(uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len)
+{
+    spi_special_receive_data_dma(DMAC_CHANNEL0, DMAC_CHANNEL1, spi_bus_no, spi_chip_select, cmd_buff, cmd_len, rx_buff, rx_len);
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_send_data_enhanced(uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len)
+{
+    spi_special_send_data(spi_bus_no, spi_chip_select, cmd_buff, cmd_len, tx_buff, tx_len);
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_send_data_enhanced_dma(uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len)
+{
+    spi_special_send_data_dma(DMAC_CHANNEL0, spi_bus_no, spi_chip_select, cmd_buff, cmd_len, tx_buff, tx_len);
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_init(uint8_t spi_index, uint8_t spi_ss)
+{
+    spi_bus_no = spi_index;
+    spi_chip_select = spi_ss;
+    spi_master_config(spi_bus_no, SPI_MODE_0, SPI_FF_STANDARD, DATALENGTH);
+    w25qxx_page_program_fun = w25qxx_page_program;
+    w25qxx_read_fun = w25qxx_stand_read_data;
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_init_dma(uint8_t spi_index, uint8_t spi_ss)
+{
+    spi_bus_no = spi_index;
+    spi_chip_select = spi_ss;
+    spi_master_config(spi_bus_no, SPI_MODE_0, SPI_FF_STANDARD, DATALENGTH);
+    w25qxx_page_program_fun = w25qxx_page_program_dma;
+    w25qxx_read_fun = w25qxx_stand_read_data;
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_read_id(uint8_t *manuf_id, uint8_t *device_id)
+{
+    uint8_t cmd[4] = {READ_ID, 0x00, 0x00, 0x00};
+    uint8_t data[2] = {0};
+
+    w25qxx_receive_data(cmd, 4, data, 2);
+    *manuf_id = data[0];
+    *device_id = data[1];
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_read_id_dma(uint8_t *manuf_id, uint8_t *device_id)
+{
+    uint8_t cmd[4] = {READ_ID, 0x00, 0x00, 0x00};
+    uint8_t data[2] = {0};
+
+    w25qxx_receive_data_dma(cmd, 4, data, 2);
+    *manuf_id = data[0];
+    *device_id = data[1];
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_write_enable(void)
+{
+    uint8_t cmd[1] = {WRITE_ENABLE};
+
+    w25qxx_send_data(cmd, 1, 0, 0);
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_write_enable_dma(void)
+{
+    uint8_t cmd[1] = {WRITE_ENABLE};
+
+    w25qxx_send_data_dma(cmd, 1, 0, 0);
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_write_status_reg(uint8_t reg1_data, uint8_t reg2_data)
+{
+    uint8_t cmd[3] = {WRITE_REG1, reg1_data, reg2_data};
+
+    w25qxx_write_enable();
+    w25qxx_send_data(cmd, 3, 0, 0);
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_write_status_reg_dma(uint8_t reg1_data, uint8_t reg2_data)
+{
+    uint8_t cmd[3] = {WRITE_REG1, reg1_data, reg2_data};
+
+    w25qxx_write_enable_dma();
+    w25qxx_send_data_dma(cmd, 3, 0, 0);
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_read_status_reg1(uint8_t *reg_data)
+{
+    uint8_t cmd[1] = {READ_REG1};
+    uint8_t data[1] = {0};
+
+    w25qxx_receive_data(cmd, 1, data, 1);
+    *reg_data = data[0];
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_read_status_reg1_dma(uint8_t *reg_data)
+{
+    uint8_t cmd[1] = {READ_REG1};
+    uint8_t data[1] = {0};
+
+    w25qxx_receive_data_dma(cmd, 1, data, 1);
+    *reg_data = data[0];
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_read_status_reg2(uint8_t *reg_data)
+{
+    uint8_t cmd[1] = {READ_REG2};
+    uint8_t data[1] = {0};
+
+    w25qxx_receive_data(cmd, 1, data, 1);
+    *reg_data = data[0];
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_read_status_reg2_dma(uint8_t *reg_data)
+{
+    uint8_t cmd[1] = {READ_REG2};
+    uint8_t data[1] = {0};
+
+    w25qxx_receive_data_dma(cmd, 1, data, 1);
+    *reg_data = data[0];
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_is_busy(void)
+{
+    uint8_t status = 0;
+
+    w25qxx_read_status_reg1(&status);
+    if (status & REG1_BUSY_MASK)
+        return W25QXX_BUSY;
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_is_busy_dma(void)
+{
+    uint8_t status = 0;
+
+    w25qxx_read_status_reg1_dma(&status);
+    if (status & REG1_BUSY_MASK)
+        return W25QXX_BUSY;
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_sector_erase(uint32_t addr)
+{
+    uint8_t cmd[4] = {SECTOR_ERASE};
+
+    cmd[1] = (uint8_t)(addr >> 16);
+    cmd[2] = (uint8_t)(addr >> 8);
+    cmd[3] = (uint8_t)(addr);
+    w25qxx_write_enable();
+    w25qxx_send_data(cmd, 4, 0, 0);
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_sector_erase_dma(uint32_t addr)
+{
+    uint8_t cmd[4] = {SECTOR_ERASE};
+
+    cmd[1] = (uint8_t)(addr >> 16);
+    cmd[2] = (uint8_t)(addr >> 8);
+    cmd[3] = (uint8_t)(addr);
+    w25qxx_write_enable_dma();
+    w25qxx_send_data_dma(cmd, 4, 0, 0);
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_32k_block_erase(uint32_t addr)
+{
+    uint8_t cmd[4] = {BLOCK_32K_ERASE};
+
+    cmd[1] = (uint8_t)(addr >> 16);
+    cmd[2] = (uint8_t)(addr >> 8);
+    cmd[3] = (uint8_t)(addr);
+    w25qxx_write_enable();
+    w25qxx_send_data(cmd, 4, 0, 0);
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_64k_block_erase(uint32_t addr)
+{
+    uint8_t cmd[4] = {BLOCK_64K_ERASE};
+
+    cmd[1] = (uint8_t)(addr >> 16);
+    cmd[2] = (uint8_t)(addr >> 8);
+    cmd[3] = (uint8_t)(addr);
+    w25qxx_write_enable();
+    w25qxx_send_data(cmd, 4, 0, 0);
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_chip_erase(void)
+{
+    uint8_t cmd[1] = {CHIP_ERASE};
+
+    w25qxx_write_enable();
+    w25qxx_send_data(cmd, 1, 0, 0);
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_enable_quad_mode(void)
+{
+    uint8_t reg_data = 0;
+
+    w25qxx_read_status_reg2(&reg_data);
+    if (!(reg_data & REG2_QUAL_MASK))
+    {
+        reg_data |= REG2_QUAL_MASK;
+        w25qxx_write_status_reg(0x00, reg_data);
+    }
+    w25qxx_page_program_fun = w25qxx_quad_page_program;
+    w25qxx_read_fun = w25qxx_quad_read_data;
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_enable_quad_mode_dma(void)
+{
+    uint8_t reg_data = 0;
+
+    w25qxx_read_status_reg2_dma(&reg_data);
+    if (!(reg_data & REG2_QUAL_MASK))
+    {
+        reg_data |= REG2_QUAL_MASK;
+        w25qxx_write_status_reg_dma(0x00, reg_data);
+    }
+    w25qxx_page_program_fun = w25qxx_quad_page_program_dma;
+    w25qxx_read_fun = w25qxx_quad_read_data;
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_disable_quad_mode(void)
+{
+    uint8_t reg_data = 0;
+
+    w25qxx_read_status_reg2(&reg_data);
+    if (reg_data & REG2_QUAL_MASK)
+    {
+        reg_data &= (~REG2_QUAL_MASK);
+        w25qxx_write_status_reg(0x00, reg_data);
+    }
+    w25qxx_page_program_fun = w25qxx_page_program;
+    w25qxx_read_fun = w25qxx_stand_read_data;
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length)
+{
+    uint8_t cmd[4] = {PAGE_PROGRAM};
+
+    cmd[1] = (uint8_t)(addr >> 16);
+    cmd[2] = (uint8_t)(addr >> 8);
+    cmd[3] = (uint8_t)(addr);
+    w25qxx_write_enable();
+    w25qxx_send_data(cmd, 4, data_buf, length);
+    while (w25qxx_is_busy() == W25QXX_BUSY)
+        ;
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_page_program_dma(uint32_t addr, uint8_t *data_buf, uint32_t length)
+{
+    uint8_t cmd[4] = {PAGE_PROGRAM};
+
+    cmd[1] = (uint8_t)(addr >> 16);
+    cmd[2] = (uint8_t)(addr >> 8);
+    cmd[3] = (uint8_t)(addr);
+    w25qxx_write_enable_dma();
+    w25qxx_send_data_dma(cmd, 4, data_buf, length);
+    while (w25qxx_is_busy_dma() == W25QXX_BUSY)
+        ;
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_quad_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length)
+{
+    uint32_t cmd[2] = {0};
+
+    cmd[0] = QUAD_PAGE_PROGRAM;
+    cmd[1] = addr;
+    w25qxx_write_enable();
+    spi_set_tmod(spi_bus_no, SPI_TMOD_TRANS);
+    spi_set_frame_format(spi_bus_no, SPI_FF_QUAD);
+    spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 0/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/);
+    w25qxx_send_data_enhanced(cmd, 2, data_buf, length);
+    spi_set_frame_format(spi_bus_no, SPI_FF_STANDARD);
+    while (w25qxx_is_busy() == W25QXX_BUSY)
+        ;
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_quad_page_program_dma(uint32_t addr, uint8_t *data_buf, uint32_t length)
+{
+    uint32_t cmd[2] = {0};
+
+    cmd[0] = QUAD_PAGE_PROGRAM;
+    cmd[1] = addr;
+    w25qxx_write_enable_dma();
+    spi_set_tmod(spi_bus_no, SPI_TMOD_TRANS);
+    spi_set_frame_format(spi_bus_no, SPI_FF_QUAD);
+    spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 0/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/);
+    w25qxx_send_data_enhanced_dma(cmd, 2, data_buf, length);
+    spi_set_frame_format(spi_bus_no, SPI_FF_STANDARD);
+    while (w25qxx_is_busy_dma() == W25QXX_BUSY)
+        ;
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_sector_program(uint32_t addr, uint8_t *data_buf)
+{
+    uint8_t index = 0;
+
+    for (index = 0; index < w25qxx_FLASH_PAGE_NUM_PER_SECTOR; index++)
+    {
+        w25qxx_page_program_fun(addr, data_buf, w25qxx_FLASH_PAGE_SIZE);
+        addr += w25qxx_FLASH_PAGE_SIZE;
+        data_buf += w25qxx_FLASH_PAGE_SIZE;
+    }
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t *data_buf, uint32_t length)
+{
+    uint32_t sector_addr = 0;
+    uint32_t sector_offset = 0;
+    uint32_t sector_remain = 0;
+    uint32_t write_len = 0;
+    uint32_t index = 0;
+    uint8_t *pread = NULL;
+    uint8_t *pwrite = NULL;
+    uint8_t swap_buf[w25qxx_FLASH_SECTOR_SIZE] = {0};
+
+    while (length)
+    {
+        sector_addr = addr & (~(w25qxx_FLASH_SECTOR_SIZE - 1));
+        sector_offset = addr & (w25qxx_FLASH_SECTOR_SIZE - 1);
+        sector_remain = w25qxx_FLASH_SECTOR_SIZE - sector_offset;
+        write_len = ((length < sector_remain) ? length : sector_remain);
+        w25qxx_read_fun(sector_addr, swap_buf, w25qxx_FLASH_SECTOR_SIZE);
+        pread = swap_buf + sector_offset;
+        pwrite = data_buf;
+        for (index = 0; index < write_len; index++)
+        {
+            if ((*pwrite) != ((*pwrite) & (*pread)))
+            {
+                w25qxx_sector_erase(sector_addr);
+                while (w25qxx_is_busy() == W25QXX_BUSY)
+                    ;
+                break;
+            }
+            pwrite++;
+            pread++;
+        }
+        if (write_len == w25qxx_FLASH_SECTOR_SIZE)
+        {
+            w25qxx_sector_program(sector_addr, data_buf);
+        }
+        else
+        {
+            pread = swap_buf + sector_offset;
+            pwrite = data_buf;
+            for (index = 0; index < write_len; index++)
+                *pread++ = *pwrite++;
+            w25qxx_sector_program(sector_addr, swap_buf);
+        }
+        length -= write_len;
+        addr += write_len;
+        data_buf += write_len;
+    }
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_write_data_direct(uint32_t addr, uint8_t *data_buf, uint32_t length)
+{
+    uint32_t page_remain = 0;
+    uint32_t write_len = 0;
+
+    while (length)
+    {
+        page_remain = w25qxx_FLASH_PAGE_SIZE - (addr & (w25qxx_FLASH_PAGE_SIZE - 1));
+        write_len = ((length < page_remain) ? length : page_remain);
+        w25qxx_page_program_fun(addr, data_buf, write_len);
+        length -= write_len;
+        addr += write_len;
+        data_buf += write_len;
+    }
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_write_data_direct_dma(uint32_t addr, uint8_t *data_buf, uint32_t length)
+{
+    uint32_t page_remain = 0;
+    uint32_t write_len = 0;
+
+    while (length)
+    {
+        page_remain = w25qxx_FLASH_PAGE_SIZE - (addr & (w25qxx_FLASH_PAGE_SIZE - 1));
+        write_len = ((length < page_remain) ? length : page_remain);
+        w25qxx_page_program_fun(addr, data_buf, write_len);
+        length -= write_len;
+        addr += write_len;
+        data_buf += write_len;
+    }
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t _w25qxx_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode)
+{
+    uint32_t cmd[2] = {0};
+
+    switch (mode)
+    {
+        case W25QXX_STANDARD:
+            *(((uint8_t *)cmd) + 0) = READ_DATA;
+            *(((uint8_t *)cmd) + 1) = (uint8_t)(addr >> 16);
+            *(((uint8_t *)cmd) + 2) = (uint8_t)(addr >> 8);
+            *(((uint8_t *)cmd) + 3) = (uint8_t)(addr >> 0);
+            w25qxx_receive_data((uint8_t *)cmd, 4, data_buf, length);
+            break;
+        case W25QXX_STANDARD_FAST:
+            *(((uint8_t *)cmd) + 0) = FAST_READ;
+            *(((uint8_t *)cmd) + 1) = (uint8_t)(addr >> 16);
+            *(((uint8_t *)cmd) + 2) = (uint8_t)(addr >> 8);
+            *(((uint8_t *)cmd) + 3) = (uint8_t)(addr >> 0);
+            *(((uint8_t *)cmd) + 4) = 0xFF;
+            w25qxx_receive_data((uint8_t *)cmd, 5, data_buf, length);
+            break;
+        case W25QXX_DUAL:
+            cmd[0] = FAST_READ_DUAL_OUTPUT;
+            cmd[1] = addr;
+            spi_set_tmod(spi_bus_no, SPI_TMOD_RECV);
+            spi_set_frame_format(spi_bus_no, SPI_FF_DUAL);
+            spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 8/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/);
+            w25qxx_receive_data_enhanced(cmd, 2, data_buf, length);
+            break;
+        case W25QXX_DUAL_FAST:
+            cmd[0] = FAST_READ_DUAL_IO;
+            cmd[1] = addr << 8;
+            spi_set_tmod(spi_bus_no, SPI_TMOD_RECV);
+            spi_set_frame_format(spi_bus_no, SPI_FF_DUAL);
+            spi_trans_config(spi_bus_no, 8/*instrction length*/, 32/*address length*/, 0/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/);
+            w25qxx_receive_data_enhanced(cmd, 2, data_buf, length);
+            break;
+        case W25QXX_QUAD:
+            cmd[0] = FAST_READ_QUAL_OUTPUT;
+            cmd[1] = addr;
+            spi_set_tmod(spi_bus_no, SPI_TMOD_RECV);
+            spi_set_frame_format(spi_bus_no, SPI_FF_QUAD);
+            spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 8/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/);
+            w25qxx_receive_data_enhanced(cmd, 2, data_buf, length);
+            break;
+        case W25QXX_QUAD_FAST:
+            cmd[0] = FAST_READ_QUAL_IO;
+            cmd[1] = addr << 8;
+            spi_set_tmod(spi_bus_no, SPI_TMOD_RECV);
+            spi_set_frame_format(spi_bus_no, SPI_FF_QUAD);
+            spi_trans_config(spi_bus_no, 8/*instrction length*/, 32/*address length*/, 4/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/);
+            w25qxx_receive_data_enhanced(cmd, 2, data_buf, length);
+            break;
+    }
+    spi_set_frame_format(spi_bus_no, SPI_AITM_STANDARD);
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_read_data_dma_less_1000bytes(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode)
+{
+    uint32_t cmd[2] = {0};
+
+    switch (mode) {
+        case W25QXX_STANDARD:
+            *(((uint8_t *)cmd) + 0) = READ_DATA;
+            *(((uint8_t *)cmd) + 1) = (uint8_t)(addr >> 16);
+            *(((uint8_t *)cmd) + 2) = (uint8_t)(addr >> 8);
+            *(((uint8_t *)cmd) + 3) = (uint8_t)(addr >> 0);
+            w25qxx_receive_data_dma((uint8_t *)cmd, 4, data_buf, length);
+            break;
+        case W25QXX_STANDARD_FAST:
+            *(((uint8_t *)cmd) + 0) = FAST_READ;
+            *(((uint8_t *)cmd) + 1) = (uint8_t)(addr >> 16);
+            *(((uint8_t *)cmd) + 2) = (uint8_t)(addr >> 8);
+            *(((uint8_t *)cmd) + 3) = (uint8_t)(addr >> 0);
+            *(((uint8_t *)cmd) + 4) = 0xFF;
+            w25qxx_receive_data_dma((uint8_t *)cmd, 5, data_buf, length);
+            break;
+        case W25QXX_DUAL:
+            cmd[0] = FAST_READ_DUAL_OUTPUT;
+            cmd[1] = addr;
+            spi_set_tmod(spi_bus_no, SPI_TMOD_RECV);
+            spi_set_frame_format(spi_bus_no, SPI_FF_DUAL);
+            spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 8/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/);
+            w25qxx_receive_data_enhanced_dma(cmd, 2, data_buf, length);
+            break;
+        case W25QXX_DUAL_FAST:
+            cmd[0] = FAST_READ_DUAL_IO;
+            cmd[1] = addr << 8;
+            spi_set_tmod(spi_bus_no, SPI_TMOD_RECV);
+            spi_set_frame_format(spi_bus_no, SPI_FF_DUAL);
+            spi_trans_config(spi_bus_no, 8/*instrction length*/, 32/*address length*/, 0/*wait cycles*/, SPI_AITM_ADDR_STANDARD/*spi address trans mode*/);
+            w25qxx_receive_data_enhanced_dma(cmd, 2, data_buf, length);
+            break;
+        case W25QXX_QUAD:
+            cmd[0] = FAST_READ_QUAL_OUTPUT;
+            cmd[1] = addr;
+            spi_set_tmod(spi_bus_no, SPI_TMOD_RECV);
+            spi_set_frame_format(spi_bus_no, SPI_FF_QUAD);
+            spi_trans_config(spi_bus_no, 8/*instrction length*/, 24/*address length*/, 8/*wait cycles*/, SPI_AITM_STANDARD/*spi address trans mode*/);
+            w25qxx_receive_data_enhanced_dma(cmd, 2, data_buf, length);
+
+            break;
+        case W25QXX_QUAD_FAST:
+            cmd[0] = FAST_READ_QUAL_IO;
+            cmd[1] = addr << 8;
+            spi_set_tmod(spi_bus_no, SPI_TMOD_RECV);
+            spi_set_frame_format(spi_bus_no, SPI_FF_QUAD);
+            spi_trans_config(spi_bus_no, 8/*instrction length*/, 32/*address length*/, 4/*wait cycles*/, SPI_AITM_ADDR_STANDARD/*spi address trans mode*/);
+            w25qxx_receive_data_enhanced_dma(cmd, 2, data_buf, length);
+            break;
+    }
+    spi_set_frame_format(spi_bus_no, SPI_FF_STANDARD);
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode)
+{
+    uint32_t len = 0;
+
+    while (length)
+    {
+        len = ((length >= 0x010000) ? 0x010000 : length);
+        _w25qxx_read_data(addr, data_buf, len, mode);
+        addr += len;
+        data_buf += len;
+        length -= len;
+    }
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_read_data_dma(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode)
+{
+    uint32_t len = 0;
+
+    while (length)
+    {
+        len = ((length >= 0x010000) ? 0x010000 : length);
+        w25qxx_read_data_dma_less_1000bytes(addr, data_buf, len, mode);
+        addr += len;
+        data_buf += len;
+        length -= len;
+    }
+    return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_stand_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length)
+{
+    return w25qxx_read_data(addr, data_buf, length, W25QXX_STANDARD_FAST);
+}
+
+static enum w25qxx_status_t w25qxx_quad_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length)
+{
+    return w25qxx_read_data(addr, data_buf, length, W25QXX_QUAD_FAST);
+}
+
+enum w25qxx_status_t w25qxx_enable_xip_mode(void)
+{
+    if (spi_handle != spi[3])
+        return W25QXX_ERROR;
+
+    spi_handle->xip_ctrl = (0x01 << 29) | (0x02 << 26) | (0x01 << 23) | (0x01 << 22) | (0x04 << 13) |
+               (0x01 << 12) | (0x02 << 9) | (0x06 << 4) | (0x01 << 2) | 0x02;
+    spi_handle->xip_incr_inst = 0xEB;
+    spi_handle->xip_mode_bits = 0x00;
+    spi_handle->xip_ser = 0x01;
+    spi_handle->ssienr = 0x01;
+    sysctl->peri.spi3_xip_en = 1;
+    return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_disable_xip_mode(void)
+{
+    sysctl->peri.spi3_xip_en = 0;
+    return W25QXX_OK;
+}
+

+ 71 - 0
lib/math/fastexp.c

@@ -0,0 +1,71 @@
+/* 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.
+ */
+
+#include "fastexp.h"
+#include <stdint.h>
+
+static inline float _fast_exp2f(float in)
+{
+    static const float p1 = 0.0f;
+    static const float p2 = 0.0f;
+    static const float p3 = 0.0f;
+    static const float p4 = 0.0f;
+    static const float p5 = 0.0f;
+
+    float x1 = in;
+    float x2 = x1 * in;
+    float x3 = x2 * in;
+    float x4 = x3 * in;
+
+    return x4 * p1 + x3 * p2 + x2 * p3 + x1 * p4 + p5;
+}
+
+
+float fast_exp2f(float x)
+{
+    union _float {
+        float f;
+        struct {
+            uint32_t frac : 23;
+            uint32_t expo : 8;
+            uint32_t sign : 1;
+        } data;
+    };
+
+    if (x < 0)
+        return 1.0f / fast_exp2f(-x);
+
+    union _float f = {.f = 1.0f};
+
+    f.data.expo = (int)x + 127;
+
+    return _fast_exp2f(x - (int)x) * f.f;
+}
+
+
+float fast_expf(float x)
+{
+    extern float __ieee754_expf(float x);
+
+    return __ieee754_expf(x);
+}
+
+
+float fast_powf(float base, float expo)
+{
+    extern float __ieee754_powf(float base, float expo);
+
+    return __ieee754_powf(base, expo);
+}

+ 116 - 0
lib/math/fastexp.h

@@ -0,0 +1,116 @@
+/* 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.
+ */
+
+#ifndef KENDRYTE_FAST_EXP
+#define KENDRYTE_FAST_EXP
+
+#include <math.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * calc exp2f(x)
+ **/
+float fast_exp2f(float x);
+
+/**
+ * calc expf(x)
+ **/
+float fast_expf(float x);
+
+/**
+ * calc powf(base,expo)
+ **/
+float fast_powf(float base, float expo);
+
+/**
+ * calc exp2(x)
+ **/
+static inline double fast_exp2(double x)
+{
+    return fast_exp2f((float)x);
+}
+
+/**
+ * calc exp(x)
+ **/
+static inline double fast_exp(double x)
+{
+    return fast_expf((float)x);
+}
+
+/**
+ * calc pow(base,expo)
+ **/
+static inline double fast_pow(double base, double expo)
+{
+    return fast_powf((float)base, (float)expo);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+#include <forward_list>
+namespace std{
+    template < typename... Args >
+    auto fast_pow(Args && ... args)->decltype(::fast_pow(std::forward < Args > (args)...)) {
+        return ::fast_pow(std::forward < Args > (args)...);
+    }
+
+    template < typename... Args >
+    auto fast_powf(Args && ... args)->decltype(::fast_powf(std::forward < Args > (args)...)) {
+        return ::fast_powf(std::forward < Args > (args)...);
+    }
+
+    template < typename... Args >
+    auto fast_exp(Args && ... args)->decltype(::fast_exp(std::forward < Args > (args)...)) {
+        return ::fast_exp(std::forward < Args > (args)...);
+    }
+
+    template < typename... Args >
+    auto fast_expf(Args && ... args)->decltype(::fast_expf(std::forward < Args > (args)...)) {
+        return ::fast_expf(std::forward < Args > (args)...);
+    }
+
+    template < typename... Args >
+    auto fast_exp2(Args && ... args)->decltype(fast_exp2(std::forward < Args > (args)...)) {
+        return ::fast_exp2(std::forward < Args > (args)...);
+    }
+
+    template < typename... Args >
+    auto fast_exp2f(Args && ... args)->decltype(::fast_exp2f(std::forward < Args > (args)...)) {
+        return ::fast_exp2f(std::forward < Args > (args)...);
+    }
+}
+#endif
+
+
+
+#ifdef CONFIG_FAST_EXP_OVERRIDE
+#define pow fast_pow
+#define powf fast_powf
+#define exp fast_exp
+#define expf fast_expf
+#define exp2 fast_exp2
+#define exp2f fast_exp2f
+
+
+#endif
+
+#endif

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor