diff --git a/.cproject b/.cproject index c9dae9d..0385040 100644 --- a/.cproject +++ b/.cproject @@ -233,10 +233,14 @@ - + ${PWD}/k210-freertos/BUILD.sh + + + + true false @@ -249,8 +253,6 @@ ${PWD}/k210-freertos/CLEAN.sh - - true false @@ -259,12 +261,14 @@ - + ${PWD}/k210-freertos/BUILD.sh -v + + true false @@ -279,8 +283,6 @@ -j16 - - true false @@ -295,8 +297,6 @@ -v -j16 - - true false diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs index 6caa44c..b82072b 100644 --- a/.settings/org.eclipse.core.resources.prefs +++ b/.settings/org.eclipse.core.resources.prefs @@ -1,4 +1,6 @@ eclipse.preferences.version=1 +encoding//firmware/kflash.py=utf-8 encoding//k210-freertos/MPyTerm.py=utf-8 encoding//k210-freertos/kflash.py=utf-8 +encoding//k210-freertos/ktool.py=utf-8 encoding//micropython/docs/conf.py=utf-8 diff --git a/Kboot/CMakeLists.txt b/Kboot/CMakeLists.txt new file mode 100644 index 0000000..aacf504 --- /dev/null +++ b/Kboot/CMakeLists.txt @@ -0,0 +1,32 @@ +# DO NOT MODIFY THIS FILE, IT WILL BE OVERRIDE!!! + +# set this will supress some warnings +set(BUILDING_SDK "yes" CACHE INTERNAL "") + +# basic config +if (NOT PROJ) + get_filename_component(PROJ ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY) + get_filename_component(PROJ ${PROJ} NAME) + string(REPLACE " " "_" PROJ ${PROJ}) + message(STATUS "PROJ not set, use ${PROJ} as PROJ. Also, you can set it manually. e.g. -DPROJ=hello_world") +else() + message("PROJ = ${PROJ}") +endif () +cmake_minimum_required(VERSION 3.0) + +include(./cmake/common.cmake) +project(${PROJ} C ASM) + +# config self use headers +include(./cmake/macros.internal.cmake) +header_directories(${SDK_ROOT}/lib) +header_directories(src/${PROJ}) +header_directories(kendryte-standalone-demo/${PROJ}) +# build library first +add_subdirectory(lib) + +# compile project +add_source_files(src/${PROJ}/*.c src/${PROJ}/*.s src/${PROJ}/*.S src/${PROJ}/*.cpp) +add_source_files(kendryte-standalone-demo/${PROJ}/*.c kendryte-standalone-demo/${PROJ}/*.s kendryte-standalone-demo/${PROJ}/*.S kendryte-standalone-demo/${PROJ}/*.cpp) +include(./cmake/executable.cmake) + diff --git a/Kboot/Kboot.md b/Kboot/Kboot.md new file mode 100644 index 0000000..bc16e48 --- /dev/null +++ b/Kboot/Kboot.md @@ -0,0 +1,182 @@ +# Kboot + +**Kboot** is a small applications (< 8KB) which enables loading and executing applications from any K210 SPI Flash location. + +## Features + +* Load and execute K210 application stored at any location in SPI Flash. +* Application to be loaded is chosen from the list of available applications in **Kboot configuration sector**. +* Multiple criteria application validity check is performed when selecting the application. +* If no valid application is found **default application** is loaded and executed. +* The **interactive mode** can be enabled in which, based on the specific **Pin** state, the user can choose which application to load and execute from the list of found applications. +
+ +## K210 Boot process when using **kboot** + +* After reset, the **1st part** (stage #0) of **Kboot** application is loaded by **K210 ROM** to SRAM address **`0x80000000`** and executed. +* SPI Flash driver is initialized in **XiP** mode. +* The **2nd part** (stage #1) of **Kboot** application is loaded to high SRAM address **`0x805E0000`** and the execution is continued fram that address. +* If allowed by configuration, **Boot Pin** state is checked and saved
If Boot Pin is activated (pulled to GND) **interactive mode** is enabled. +* **Configuration sector** is scanned for valid applications.
Following actions are performed: + * Configuration entry ID is checked + * Application Flash address is cheched for valid range + * Application size is checked for valid range + * If **Size** flag is set, application size is checked agains the acctual size written in application's _Flash block_. + * Application flags are saved + * Application _Flash block_ ***** is checked for valid format + * If **CRC32** flag is set, application's crc32 is calculated and checked + * If **SHA256** flag is set, application's SHA256 hash is calculated and checked +* If no valid application is found, the **backup** configuration sector is scanned. +* If all checks passes, the application is marked as **valid**. +* If **not in interactive mode**, configuration sector scan is terminated as soon as the first valid, flagged as **active** application is found and that application is loaded and executed. +* If in **interactive mode**, all configuration sector entries are scanned and the user is prompted to select which one to load and execute. +* If **no valid application** is found, the **default application** is loaded and executed +* If the **default application** fails the application test, the system is **halted** + +> ***** each application stored in SPI Flash has the following format: +> +> | Byte offset | Size | Name | Content | +> | ---: | ---: | :---: | :--- | +> | `0` | `1` | AES_FLAG | AES cipher flag, for use with **Kboot** must be `0` | +> | `1` | `4` | APP_SIZE | Application code size | +> | `5` | `APP_SIZE` | APP_CODE | Application code | +> | `APP_SIZE + 5` | `32` | SHA_HASH | Application SHA256 hash | +> +> All applications flashed with **ktool.py** or **kflash.py** have such format. + +
+ +## K210 SPI Flash layout + +The following SPI Flash layout must be used when using **Kboot* + +| From | To | Length | Comment | +| ---: | ---: | ---: | :--- | +| `0x00000000` | `0x00000FFF` | 4K | 1st part of **Kboot** application, **stage #0** code | +| `0x00001000` | `0x00003FFF` | 12K | 2nd part of **Kboot** application, **stage #1** code | +| `0x00004000` | `0x00004FFF` | 4K | **main** boot configuration sector | +| `0x00005000` | `0x00005FFF` | 4K | **backup** boot configuration sector | +| `0x00006000` | `0x0000FFFF` | 40K | reserved, user data etc. | +| `0x00010000` | `DEF_APP_END` | --- | **default application** code | +| >`DEF_APP_END` | `FLASH_END` | --- | user area, application(s) code, file system(s), user data etc. | + +
+ +## **Boot configuration** sector + +Boot configuration used by **Kboot** is stored in one SPI Flash sector (4KB) at fixed Flash address (`0x00004000`).
+One **backup** configuration sector is also used for security reasons, stored in one SPI Flash sector (4KB) at fixed Flash address (`0x00005000`).
+ +The configuration sector consists of **`8`** _application entries_ occupying **`32`** bytes each.
+After the last application entry the **config flags** entry is placed, one 32bit value.
+ +Configuration sector layout: + +| Offset | To | Length | Comment | +| ---: | ---: | ---: | :--- | +| `0x000` | `01F` | `32` | application entry #0 | +| `0x020` | `03F` | `32` | application entry #1 | +| `0x040` | `05F` | `32` | application entry #2 | +| `0x060` | `07F` | `32` | application entry #3 | +| `0x080` | `09F` | `32` | application entry #4 | +| `0x0A0` | `0BF` | `32` | application entry #5 | +| `0x0C0` | `0DF` | `32` | application entry #6 | +| `0x0E0` | `0FF` | `32` | application entry #7 | +| `0x100` | `103` | `4` | **config flags** | +| `0x104` | `11F` | `4` | reserved | +| `0x120` | `11F` | `4` | not used, user data | +
+ +The format of each _application entry_ in configuration sector is as follows: + +| Offset | Length | Comment | +| ---: | ---: | :--- | +| `0` | `4` | Configuration entry **ID** (bits 4-31) + entry **flags** (bits 0-4) | +| `4` | `4` | Application address in SPI Flash | +| `8` | `4` | Application size in SPI Flash. This is the size of the application's **`.bin`** file | +| `12` | `4` | Application's CRC32 value (32bits) | +| `16` | `16` | Null terminated application name or description | + +_Notes:_
+Configuration entry **ID** must have a value of **`0x5AA5D0C0`** for entry to be recognized as valid.
+Application addres must be in range **`0x10000`** ~ **`0x800000`** ( 64KB ~ 8MB ).
+Application size must be in range **`0x4000`** ~ **`0x300000`** ( 16KB ~ 3MB ).
+Application CRC32 value is used only if **CRC32** flag is set.

+ +If **config flags** at offset `0x100` in **configuration sector** is set to configuration entry **ID** (**`0x5AA5D0C0`**), **interractive mode** will be disabled, **boot Pin* will not be checked and nothing will be printed during the boot process. +Configuration entry **flags**: + +| Bit | Comment | +| :---: | :--- | +| `0` | **Active** flag, if set the application will be loaded and executed.
If multiple entries have **active** flag set, the first one will be loaded ad executed | +| `1` | **CRC32** flag, if set the application's CRC32 value will be calculated and compared with the value in the configuration entry | +| `2` | **AES256** flag, if set the application's AES256 hash value will be calculated and compared with the value stored in flash after the application code (`SHA_HASH`) | +| `3` | **Size** flag, if set the application size specified in configuration entry must match the application size present in application's _Flash block_ | + +**_Warning:_** all 32-bit values in the configuration sector entries must be written in **big-endian** format. + +
+ +## Default application + +If in the boot process **no valid application** was found in the **configuration sector**, the **default application** is loaded and executed.
+**_The default application should try to check if loading it was **intended** or it was result of an error condition, in which case it should try to correct the issue._** + +
+ +## Building the applications to be used with _Kboot_ + +Nothing special must be done to build the applications which are going to be used with **Kboot**.
+All applications built with Kendryte **Standalone SDK** or **FreeRTOS SDK** should run without issues.
+ +The application can check if the **Kboot** system is used by reading the 2nd SPI Flash sector (at address **`0x1000`**).
+At offset `0x09` the `Kboot` **id string** is positioned: **`Kboot_v1.4.1`** (version mumbers may be different).
+ +``` +[00001000] 00 B0 1F 00 00 6F 00 40 01 4B 62 6F 6F 74 5F 76 31 2E 34 2E 31 00 00 00 00 19 71 86 FC A2 F8 A6 +[00001020] F4 CA F0 CE EC D2 E8 D6 E4 DA E0 5E FC 62 F8 66 F4 6A F0 6E EC F3 27 40 F1 81 27 17 27 00 00 23 +``` + +_See the note about sector data!_ + +

+ +## Usage + +Flashing the application(s) to SPI Flash and manipulating the boot **configuration sector** should be performed from the user application.
+Accessing SPI flash from K210 application is quite easy and reliable. + + + +### Example + +**Application firmware update** + +* The condition to update the firmware is detected by the application +* Load the **boot configuration** sector, check its integrity and check the flash address and size of the currently running application +* Flash the new firmware to the **not used** SPI Flash area. The new firmware can be downloaded from remote server using WiFi or GSM, loaded from SD Card, etc ...
Use the **application block** format described above.
The application can be flashed **without** SHA256 hash, in that case do not set the **`SHA256`** flag. +* Calculate new firmware's CRC32 and/or SHA256 hash if needed. +* Flash the current **main** boot configuration sector to the **backup** boot configuration sector and check it.
It will be used by **Kboot** in case the **main** boot configuration sector which we are going to write is corrupted. +* Update (add or change entry) in the boot configuration sector with the new firmware information, set the new firmware as active and the old firmware as inactive and flash the configuration sector. +* Reset (reboot) the system to start the new firmware. + + +### Important Notes + +When reading sectors written with **ktool.p<** or **kflash.py** from SPI Flash in **normal** mode (not using **XiP** mode), the sector data may look corrupted.
+The reason is that all sector data are written with **swapped** 32-bit values (32-bit **big endian** format is used).
+To correct this, you should **swap endianess** of all 32-bit values in the sector, something like this:.
+ +``` +uint8_t buf4[4]; +for (int k=0; k<4096; k+=4) { + buf4[0] = sector[k+0]; + buf4[1] = sector[k+1]; + buf4[2] = sector[k+2]; + buf4[3] = sector[k+3]; + sector[k+0] = buf4[3]; + sector[k+1] = buf4[2]; + sector[k+2] = buf4[1]; + sector[k+3] = buf4[0]; +} +``` diff --git a/Kboot/README.md b/Kboot/README.md new file mode 100644 index 0000000..27862bf --- /dev/null +++ b/Kboot/README.md @@ -0,0 +1,204 @@ +# Kboot + +**Kboot** is a small applications which enables loading and executing applications from any K210 SPI Flash location. + +It can be used to implement firmware upgrade (OTA) or to load different (multiple) applications based on some criteria. + +Interactive mode is also provided which enables the user to select which application to load and execute from the list of stored applications. + +--- +> More details about **Kboot** are available in the [**Kboot.md**](https://github.com/loboris/Kboot/blob/master/Kboot.md). +--- + +
+ +## How to build + +Clone the repository or download and unpack the repository zip file. + +**The repository contains all the tools and sources needed to build `Kboot`.** + +The same build prerequisites must be satisfied as for building any other K210 application.
+ +Default application (**`config.bin`**, which runs if no configured aplications are found), default configuration sector (**`config.bin`**) and 3 example applications are provided.
+ +Example applications:
+**MicroPython.bin**, built with **_FreeRTOS SDK_** is expected to be found at Flash address **`0x00080000`** (512 KB),
+**dvp_ov.bin**, **_Standalone SDK_** example, is expected to be found at Flash address **`0x00280000`** (2.5 MB)
+**maixpy.bin**, built with **_Standalone SDK_**, is expected to be found at Flash address **`0x00280000`** (2.5 MB)
+ +You can flash the default application executting: + +```console +./ktool.py -p /dev/ttyUSB0 -a 65536 -b 2000000 -t default.bin +``` + +You can flash one of example aplications executing: + +```console +./ktool.py -p /dev/ttyUSB0 -a 524288 -b 2000000 -t MicroPython.bin +./ktool.py -p /dev/ttyUSB0 -a 2621440 -b 2000000 -t dvp_ov.bin +./ktool.py -p /dev/ttyUSB0 -a 2621440 -b 2000000 -t maixpy.bin +``` + +### Build from source + +* Change the working directory to the **`build`** directory. +* A simple build script **`BUILD.sh`** is provided which builds the **`Kboot`** application. +* Simply execute `BUILD.sh` +* **`kboot.kfpkg`** package will be created which includes `bootloader_lo.bin` and `bootloader_hi.bin` binaries and the default configuration. + +### Flash to K210 board + +**`kboot.kfpkg`** can be flashed to the K210 using the included [**`ktool.py`**](https://github.com/loboris/ktool).
+**_Note:_** Do not use standard **`kflash.py`**, **kboot** binaries requires flashing **4KB aligned blocks**, which is not supported by standard `kflash.py`. + +
+ +### Examples + +Build the **`Kboot`** package: + +```console +boris@UbuntuMate:/home/kboot/build$ ./BUILD.sh + + =========================== + === Building bootloader === + =========================== + +=== Running 'cmake' +=== Running 'make' +Scanning dependencies of target kendryte +[ 25%] Linking C static library libkendryte.a +[ 25%] Built target kendryte +Scanning dependencies of target bootloader_lo +[ 75%] Building C object CMakeFiles/bootloader_lo.dir/src/bootloader_lo/main.c.obj +[ 75%] Building ASM object CMakeFiles/bootloader_lo.dir/src/bootloader_lo/crt.S.obj +[100%] Linking C executable bootloader_lo +Generating .bin file ... +[100%] Built target bootloader_lo + +=== Finished +--------------------------------------------------- + text data bss dec hex filename + 496 112 8 616 268 bootloader_lo +--------------------------------------------------- + +=== Running 'cmake' +=== Running 'make' +Scanning dependencies of target kendryte +[ 14%] Linking C static library libkendryte.a +[ 14%] Built target kendryte +Scanning dependencies of target bootloader_hi +[ 28%] Building ASM object CMakeFiles/bootloader_hi.dir/src/bootloader_hi/crt.S.obj +[ 71%] Building C object CMakeFiles/bootloader_hi.dir/src/bootloader_hi/main.c.obj +[ 71%] Building C object CMakeFiles/bootloader_hi.dir/src/bootloader_hi/fpioa.c.obj +[ 71%] Building C object CMakeFiles/bootloader_hi.dir/src/bootloader_hi/gpiohs.c.obj +[ 85%] Building C object CMakeFiles/bootloader_hi.dir/src/bootloader_hi/sha256.c.obj +[100%] Linking C executable bootloader_hi +Generating .bin file ... +[100%] Built target bootloader_hi + +=== Finished +-------------------------------------------------- + text data bss dec hex filename + 6848 1264 88 8200 2008 bootloader_hi +-------------------------------------------------- + +=== Creating 'kboot.kfpkg' + +-------------------------------------------------------------------- +To flash the kboot package to K210 run: +./ktool.py -p /dev/ttyUSB0 -b 2000000 -t kboot.kfpkg + +To flash default application run: +./ktool.py -p /dev/ttyUSB0 -a 65536 -b 2000000 -t default.bin + +Default config can run applications from 512K or 2.5M flash address +Some applications are provided for testing: + +To flash MicroPython (FreeRTOS SDK) at 512K, run: +./ktool.py -p /dev/ttyUSB0 -a 524288 -b 2000000 -t MicroPython.bin +To flash dvp_ov (Standalone SDK) at 2.5M, run: +./ktool.py -p /dev/ttyUSB0 -a 2621440 -b 2000000 -t dvp_ov.bin +To flash maixpy (Standalone SDK) at 2.5M, run: +./ktool.py -p /dev/ttyUSB0 -a 2621440 -b 2000000 -t maixpy.bin + +If no app is found, default app will be run which blinks the LED(s). +-------------------------------------------------------------------- + +boris@UbuntuMate:/home/kboot/build$ +``` + +Flash **`Kboot`** package to K210 board: + +```console +boris@UbuntuMate:/home/kboot/build$ ./ktool.py -p /dev/ttyUSB0 -b 2000000 -t kboot.kfpkg +[INFO] COM Port Selected Manually: /dev/ttyUSB0 +[INFO] Default baudrate is 115200 , later it may be changed to the value you set. +[INFO] Trying to Enter K210 ROM ISP Mode... +. +[INFO] Automatically detected dan/bit/trainer + +[INFO] ROM ISP detected, loading 2nd stage ISP +[INFO] ISP loaded in 0.921s +[INFO] Starting 2nd stage ISP at 0x805e0000 +[INFO] Wait For 0.1 second for ISP to Boot +[INFO] 2nd stage ISP ok +[INFO] Selected Baudrate: 2000000 +[INFO] Baudrate changed, greeting with ISP again ... +[INFO] 2nd stage ISP ok +[INFO] Initialize K210 SPI Flash +[INFO] Flash initialized successfully +[INFO] Flash ID: 0xC86018, unique ID: 384130323209302A, size: 16 MB +[INFO] Extracting KFPKG ... +[INFO] Writing bootloader_lo.bin to Flash address 0x00000000 +[INFO] Flashing firmware block with SHA suffix +Programming BIN: |=========================================================================================================| 100.0% +[INFO] Flashed 645 B [1 chunks of 4096B] (00000000~00000FFF) in 0.137s +[INFO] Writing bootloader_hi.bin to Flash address 0x00001000 +[INFO] Flashing firmware block with SHA suffix +Programming BIN: |=========================================================================================================| 100.0% +[INFO] Flashed 8149 B [2 chunks of 4096B] (00001000~00002FFF) in 0.255s +[INFO] Writing config.bin to Flash address 0x00004000 +Programming DATA: |=========================================================================================================| 100.0% +[INFO] Flashed 4096 B [1 chunks of 4096B] (00004000~00004FFF) in 0.132s +[INFO] Writing config.bin to Flash address 0x00005000 +Programming DATA: |=========================================================================================================| 100.0% +[INFO] Flashed 4096 B [1 chunks of 4096B] (00005000~00005FFF) in 0.129s +[INFO] Rebooting... + +--- forcing DTR inactive +--- forcing RTS inactive +--- Miniterm on /dev/ttyUSB0 115200,8,N,1 --- +--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- + +K210 bootloader by LoBo v.1.4.1 + +* Find applications in MAIN parameters + 0: ' dvp_ov example', @ 0x00280000, size=77248, app_size=1679808, App ok, NOT ACTIVE + 1: ' MicroPython', @ 0x00080000, size=1744896, app_size=1789952, App ok, ACTIVE + 2: ' maixpy', @ 0x00280000, size=1681856, app_size=1679808, App ok, NOT ACTIVE + +Select the application number to load [ 0, 1, 2, d=default ] ? 1 + +* Loading app from flash at 0x00080000 (1789952 B) +* Starting at 0x80000000 ... + +M (37678) [K210_MAIN]: Default flash configuration set + +RISC-V Kendryte --------------------------------------------- + _ _ _____ _ ______ ___ ___ ______ _ _ +( ) / ) (___ ) ( ) ( __ ) ( \ / ) ( __ ) ( ) ( ) +| |_/ / ___| | | | | | | | | |\ \ /| | | |__| | \ \_/ / +| _ ) ( ____) | | | | | |**| | \_/ | | | ____) \ / +| | \ \ | |___ | | | |__| | | | | | | | | | +(_) \_) (_____) (_) (______) (_) (_) (_) (_) +------------------------------------------------------------- +MicroPython-FreeRTOS by LoBo v1.11.12 (two MPY tasks) +----------------------------------------------------- + +MicroPython 1.11.12 (1abe503-dirty) built on 2020-01-02; Sipeed_board with Kendryte-K210 +Type "help()" for more information. +>>> +``` diff --git a/Kboot/cmake/CMakeLists.txt b/Kboot/cmake/CMakeLists.txt new file mode 100644 index 0000000..64f2708 --- /dev/null +++ b/Kboot/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) diff --git a/Kboot/cmake/README.md b/Kboot/cmake/README.md new file mode 100644 index 0000000..5e5bc8b --- /dev/null +++ b/Kboot/cmake/README.md @@ -0,0 +1,3 @@ +prepend `common.cmake` before + +append `executable.cmake` after diff --git a/Kboot/cmake/common.cmake b/Kboot/cmake/common.cmake new file mode 100644 index 0000000..a4eec83 --- /dev/null +++ b/Kboot/cmake/common.cmake @@ -0,0 +1,43 @@ +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 Release) +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 () + +if (NOT NO_BOOT_LOGGING) + global_set(BOOT_LOGGING -DLOGGING_ENABLED) +endif () + +# - Debug & Release +IF (CMAKE_BUILD_TYPE STREQUAL Debug) + add_definitions(-DDEBUG=1) +ENDIF () + +# definitions in macros +add_definitions(${BOOT_LOGGING} -DCONFIG_LOG_LEVEL=LOG_NONE -DCONFIG_LOG_ENABLE -DCONFIG_LOG_COLORS -DLOG_KERNEL -D__riscv64 -DLV_CONF_INCLUDE_SIMPLE) + +# xtl options +add_definitions(-DTCB_SPAN_NO_EXCEPTIONS -DTCB_SPAN_NO_CONTRACT_CHECKING) +# nncase options +add_definitions(-DNNCASE_TARGET=k210) + +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) diff --git a/Kboot/cmake/compile-flags.cmake b/Kboot/cmake/compile-flags.cmake new file mode 100644 index 0000000..83a6776 --- /dev/null +++ b/Kboot/cmake/compile-flags.cmake @@ -0,0 +1,67 @@ +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 + -Wl,--no-relax + -T ${SDK_ROOT}/lds/kendryte.ld + ) + +# C Flags Settings +add_compile_flags(BOTH + -mcmodel=medany + -mabi=lp64f + -march=rv64imafdc + -fno-common + -ffunction-sections + -fdata-sections + -fstrict-volatile-bitfields + -fno-zero-initialized-in-bss + -ffast-math + -fno-math-errno + -fsingle-precision-constant + -fPIC + -O0 + -ggdb + ) + +add_compile_flags(C -std=gnu11 -Wno-pointer-to-int-cast) +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 + -Wno-multichar + -Wextra + -Werror=frame-larger-than=32768 + -Wno-unused-parameter + -Wno-sign-compare + -Wno-error=missing-braces + -Wno-error=return-type + -Wno-error=pointer-sign + -Wno-missing-braces + -Wno-strict-aliasing + -Wno-implicit-fallthrough + -Wno-missing-field-initializers + -Wno-int-to-pointer-cast + -Wno-error=comment + -Wno-error=logical-not-parentheses + -Wno-error=duplicate-decl-specifier + -Wno-error=parentheses + ) + + add_compile_flags(C -Wno-old-style-declaration) +else () + add_compile_flags(BOTH -L${SDK_ROOT}/include/) +endif () + diff --git a/Kboot/cmake/dump-config.cmake b/Kboot/cmake/dump-config.cmake new file mode 100644 index 0000000..8531f6c --- /dev/null +++ b/Kboot/cmake/dump-config.cmake @@ -0,0 +1,22 @@ +message("") +message("Project: ${PROJECT_NAME}") +message(" LIST_FILE=${CMAKE_PARENT_LIST_FILE}") +message(" TOOLCHAIN=${TOOLCHAIN}") +message(" KENDRYTE_IDE=${KENDRYTE_IDE}") +message(" BUILDING_SDK=${BUILDING_SDK}") +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(" CMAKE_OBJDUMP=${CMAKE_OBJDUMP}") +message(" CMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") +message("") +message(" CMAKE_C_FLAGS=${CMAKE_C_FLAGS}") +message(" CMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}") +message(" LDFLAGS=${LDFLAGS}") +message(" CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}") +message("Makefile created.") +message("") +message("") diff --git a/Kboot/cmake/executable.cmake b/Kboot/cmake/executable.cmake new file mode 100644 index 0000000..522e70b --- /dev/null +++ b/Kboot/cmake/executable.cmake @@ -0,0 +1,45 @@ +if (NOT BUILDING_SDK) + if(EXISTS ${SDK_ROOT}/libkendryte.a) + add_library(kendryte STATIC IMPORTED) + set_property(TARGET kendryte PROPERTY IMPORTED_LOCATION ${SDK_ROOT}/libkendryte.a) + include_directories(${SDK_ROOT}/include/) + else() + header_directories(${SDK_ROOT}/lib) + add_subdirectory(${SDK_ROOT}/lib) + endif() +endif () + +removeDuplicateSubstring(${CMAKE_C_FLAGS} CMAKE_C_FLAGS) +removeDuplicateSubstring(${CMAKE_CXX_FLAGS} CMAKE_CXX_FLAGS) + +message("SOURCE_FILES=${SOURCE_FILES}") +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + + +set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C) + +target_link_libraries(${PROJECT_NAME} + -Wl,--start-group + gcc m c + -Wl,--whole-archive + kendryte + -Wl,--no-whole-archive + -Wl,--end-group + ) + +if (EXISTS ${SDK_ROOT}/src/${PROJ}/project.cmake) + include(${SDK_ROOT}/src/${PROJ}/project.cmake) +endif () + +IF(SUFFIX) + SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SUFFIX ${SUFFIX}) +ENDIF() + +# 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 ...") + +# show information +include(${CMAKE_CURRENT_LIST_DIR}/dump-config.cmake) diff --git a/Kboot/cmake/fix-9985.cmake b/Kboot/cmake/fix-9985.cmake new file mode 100644 index 0000000..4402bd3 --- /dev/null +++ b/Kboot/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}") diff --git a/Kboot/cmake/ide.cmake b/Kboot/cmake/ide.cmake new file mode 100644 index 0000000..0c3db5f --- /dev/null +++ b/Kboot/cmake/ide.cmake @@ -0,0 +1,7 @@ +FILE(GLOB_RECURSE ASSEMBLY_FILES + "${CMAKE_CURRENT_LIST_DIR}/*.s" + "${CMAKE_CURRENT_LIST_DIR}/*.S" +) + +SET_PROPERTY(SOURCE ${ASSEMBLY_FILES} PROPERTY LANGUAGE C) +SET_SOURCE_FILES_PROPERTIES(${ASSEMBLY_FILES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D __riscv64") diff --git a/Kboot/cmake/macros.cmake b/Kboot/cmake/macros.cmake new file mode 100644 index 0000000..ab75e24 --- /dev/null +++ b/Kboot/cmake/macros.cmake @@ -0,0 +1,72 @@ +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 "") + +function(removeDuplicateSubstring stringIn stringOut) + separate_arguments(stringIn) + list(REMOVE_DUPLICATES stringIn) + string(REPLACE ";" " " stringIn "${stringIn}") + set(${stringOut} "${stringIn}" PARENT_SCOPE) +endfunction() + +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() diff --git a/Kboot/cmake/macros.internal.cmake b/Kboot/cmake/macros.internal.cmake new file mode 100644 index 0000000..a38b56d --- /dev/null +++ b/Kboot/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() \ No newline at end of file diff --git a/Kboot/cmake/toolchain.cmake b/Kboot/cmake/toolchain.cmake new file mode 100644 index 0000000..ea10e46 --- /dev/null +++ b/Kboot/cmake/toolchain.cmake @@ -0,0 +1,51 @@ +if (WIN32) + set(EXT ".exe") +else () + set(EXT "") +endif () + +message(STATUS "Check for RISCV toolchain ...") +if(NOT TOOLCHAIN) + find_path(_TOOLCHAIN riscv64-unknown-elf-gcc${EXT}) + global_set(TOOLCHAIN "${_TOOLCHAIN}") +elseif(NOT "${TOOLCHAIN}" MATCHES "/$") + global_set(TOOLCHAIN "${TOOLCHAIN}") +endif() + +if (NOT TOOLCHAIN) + message(FATAL_ERROR "TOOLCHAIN must be set, to absolute path of kendryte-toolchain dist/bin folder.") +endif () + +message(STATUS "Using ${TOOLCHAIN} RISCV toolchain") + +global_set(CMAKE_C_COMPILER "${TOOLCHAIN}/riscv64-unknown-elf-gcc${EXT}") +global_set(CMAKE_CXX_COMPILER "${TOOLCHAIN}/riscv64-unknown-elf-g++${EXT}") +global_set(CMAKE_LINKER "${TOOLCHAIN}/riscv64-unknown-elf-ld${EXT}") +global_set(CMAKE_AR "${TOOLCHAIN}/riscv64-unknown-elf-ar${EXT}") +global_set(CMAKE_OBJCOPY "${TOOLCHAIN}/riscv64-unknown-elf-objcopy${EXT}") +global_set(CMAKE_SIZE "${TOOLCHAIN}/riscv64-unknown-elf-size${EXT}") +global_set(CMAKE_OBJDUMP "${TOOLCHAIN}/riscv64-unknown-elf-objdump${EXT}") +if (WIN32) + if(EXISTS "${TOOLCHAIN}/make${EXT}") + global_set(CMAKE_MAKE_PROGRAM "${TOOLCHAIN}/make${EXT}") + else() + global_set(CMAKE_MAKE_PROGRAM "${TOOLCHAIN}/mingw32-make${EXT}") + endif() +endif () + +execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=crt0.o OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE CRT0_OBJ) +execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=crtbegin.o OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE CRTBEGIN_OBJ) +execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=crtend.o OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE CRTEND_OBJ) +execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=crti.o OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE CRTI_OBJ) +execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=crtn.o OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE CRTN_OBJ) + +global_set(CMAKE_C_LINK_EXECUTABLE + " \"${CRTI_OBJ}\" \"${CRTBEGIN_OBJ}\" \"${CRTEND_OBJ}\" \"${CRTN_OBJ}\" -o ") + +global_set(CMAKE_CXX_LINK_EXECUTABLE + " \"${CRTI_OBJ}\" \"${CRTBEGIN_OBJ}\" \"${CRTEND_OBJ}\" \"${CRTN_OBJ}\" -o ") + +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 () diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_2M.ld b/Kboot/lds/bootloader_hi.ld similarity index 50% rename from k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_2M.ld rename to Kboot/lds/bootloader_hi.ld index 0301458..fc99e70 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_2M.ld +++ b/Kboot/lds/bootloader_hi.ld @@ -3,28 +3,27 @@ * 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. */ - /* - * LoBo: The LENGTH specified here must be enough to run the MicroPython firmware - * including creating all static, global and dynamic variables on K210 heap - */ - - MEMORY { /* * Memory with CPU cache. - * CPU SRAM + * 64K CPU SRAM */ - ram (wxa!ri) : ORIGIN = 0x80002000, LENGTH = (0x200000-0x2000) + ram (wxari) : ORIGIN = 0x805E0000, LENGTH = 0x00008000 /* * Memory without CPU cache - * CPU SRAM + * 64K CPU SRAM */ - ram_nocache (wxa!ri) : ORIGIN = 0x40002000, LENGTH = (0x200000-0x2000) + ram_nocache (wxari) : ORIGIN = 0x405E0000, LENGTH = 0x00008000 } +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( _stack_size = 1 << 16 ); +PROVIDE( _io_start = ORIGIN(ram_nocache) ); +PROVIDE( _io_end = _io_start + LENGTH(ram_nocache) ); + /* * The OUTPUT_ARCH command specifies the machine architecture where the @@ -38,14 +37,25 @@ OUTPUT_ARCH( "riscv" ) */ 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 { - DATA PT_LOAD; - DYN_DATA PT_NULL; + ram_ro PT_LOAD; + ram_init PT_LOAD; + ram PT_NULL; } /* @@ -54,74 +64,65 @@ PHDRS */ SECTIONS { - .text.start : - { - KEEP( *(.text.start) ) - KEEP( *(.text.systick) ) - } > ram : DATA - - .init : - { - KEEP (*(SORT_NONE(.init))) - } > ram : DATA - - . = ALIGN(8); - . = .; + /* Program code segment, also known as a text segment */ .text : { - *(.text.unlikely .text.*_unlikely .text.unlikely.*) - *(.text.exit .text.exit.*) + PROVIDE( _text = ABSOLUTE(.) ); + /* Initialization code segment */ + KEEP( *(.text.start) ) + *(.text.unlikely .text.unlikely.*) *(.text.startup .text.startup.*) - *(.text.hot .text.hot.*) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } > ram : DATA - - .fini : - { - KEEP (*(SORT_NONE(.fini))) - } > ram : DATA - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } > ram : DATA - .rodata1 : { *(.rodata1) } > ram : DATA - .sdata2 : + /* Normal code segment */ + *(.text .text.*) + *(.gnu.linkonce.t.*) + + . = ALIGN(8); + PROVIDE( _etext = ABSOLUTE(.) ); + } >ram AT>ram :ram_ro + + /* Read-only data segment */ + .rodata : { - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - } > ram : DATA + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } >ram AT>ram :ram_ro + + . = ALIGN(8); + /* Exception handling */ .eh_frame : { KEEP (*(.eh_frame)) *(.eh_frame.*) . = ALIGN(8); - } > ram : DATA - .gnu_extab : { *(.gnu_extab) } > ram : DATA - .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } > ram : DATA - .exception_ranges : { *(.exception_ranges .exception_ranges*) } > ram : DATA - + } >ram AT>ram :ram_ro + .gnu_extab : { *(.gnu_extab) } >ram AT>ram :ram_ro + .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } >ram AT>ram :ram_ro + .exception_ranges : { *(.exception_ranges .exception_ranges*) } >ram AT>ram :ram_ro + + /* Init array and fini array */ .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); - } > ram : DATA + } >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)) + *(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors) PROVIDE_HIDDEN (__init_array_end = .); - } > ram : DATA + } >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 : DATA + } >ram AT>ram :ram_ro .ctors : { @@ -143,7 +144,8 @@ SECTIONS KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) - } > ram : DATA + } >ram AT>ram :ram_ro + .dtors : { KEEP (*crtbegin.o(.dtors)) @@ -151,49 +153,64 @@ SECTIONS KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) - } > ram : DATA - - . = ALIGN(64); - .data : + } >ram AT>ram :ram_ro + + . = ALIGN(8); + + .lalign : { - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } > ram : DATA - .data1 : { *(.data1) } > ram : DATA - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : + . = ALIGN(8); + PROVIDE( _data_lma = . ); + } >ram AT>ram :ram_ro + + .dalign : { - __global_pointer$ = . + 0x800; - *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) - *(.sdata .sdata.* .gnu.linkonce.s.*) - } > ram : DATA - _edata = .; PROVIDE (edata = .); - + . = ALIGN(8); + PROVIDE( _data = . ); + } >ram AT>ram :ram_init + . = ALIGN(8); - . = .; - __bss_start = .; - .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } > ram : DYN_DATA - .sbss : + + /* .data, .sdata and .srodata segment */ + .data : { - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - } > ram : DYN_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( __global_pointer$ = 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 : { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) + 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 here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 64 / 8 : 1); - } > ram : DYN_DATA - __bss_end = .; + + . = ALIGN(8); + PROVIDE( _ebss = ABSOLUTE(.) ); + } >ram AT>ram :ram PROVIDE( _tls_data = ABSOLUTE(.) ); /* @@ -210,7 +227,7 @@ SECTIONS *(.tdata .tdata.*) *(.gnu.linkonce.td.*) KEEP( *(.tdata.end) ) - } > ram : DATA + } >ram AT>ram :ram /* Thread-local bss segment, .tbss (zero-initialized tls). */ .tbss : @@ -218,7 +235,7 @@ SECTIONS *(.tbss .tbss.*) *(.gnu.linkonce.tb.*) KEEP( *(.tbss.end) ) - } > ram : DYN_DATA + } >ram AT>ram :ram /* * End of uninitalized data segement @@ -229,49 +246,18 @@ SECTIONS * Align _heap_start to cache line size */ . = ALIGN(64); - _end = .; PROVIDE( _end = ABSOLUTE(.) ); + PROVIDE( _end = ABSOLUTE(.) ); /* Leave 2 holes for stack & TLS, the size can set in kconfig */ - PROVIDE( _heap_start = ABSOLUTE(.) + _stack_size * 5 ); + + PROVIDE( _heap_start = ABSOLUTE(.) ); + /* 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 ); - - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } } diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_2_5M.ld b/Kboot/lds/bootloader_lo.ld similarity index 50% rename from k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_2_5M.ld rename to Kboot/lds/bootloader_lo.ld index d87ff66..bf2c5c4 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_2_5M.ld +++ b/Kboot/lds/bootloader_lo.ld @@ -3,28 +3,29 @@ * 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. */ - /* - * LoBo: The LENGTH specified here must be enough to run the MicroPython firmware - * including creating all static, global and dynamic variables on K210 heap - */ - - MEMORY { /* * Memory with CPU cache. - * CPU SRAM + * 64K CPU SRAM */ - ram (wxa!ri) : ORIGIN = 0x80002000, LENGTH = (0x280000-0x2000) + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 0x00008000 /* * Memory without CPU cache - * CPU SRAM + * 64K CPU SRAM */ - ram_nocache (wxa!ri) : ORIGIN = 0x40002000, LENGTH = (0x280000-0x2000) + ram_nocache (wxa!ri) : ORIGIN = 0x40000000, LENGTH = 0x00008000 } +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( _stack_size = 1 << 16 ); +PROVIDE( _io_start = ORIGIN(ram_nocache) ); +PROVIDE( _io_end = _io_start + LENGTH(ram_nocache) ); +PROVIDE( _stack_size = 1 << 15 ); +PROVIDE( _stack_start = 0x80540000 ); + /* * The OUTPUT_ARCH command specifies the machine architecture where the @@ -38,14 +39,25 @@ OUTPUT_ARCH( "riscv" ) */ 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 { - DATA PT_LOAD; - DYN_DATA PT_NULL; + ram_ro PT_LOAD; + ram_init PT_LOAD; + ram PT_NULL; } /* @@ -54,74 +66,65 @@ PHDRS */ SECTIONS { - .text.start : - { - KEEP( *(.text.start) ) - KEEP( *(.text.systick) ) - } > ram : DATA - - .init : - { - KEEP (*(SORT_NONE(.init))) - } > ram : DATA - - . = ALIGN(8); - . = .; + /* Program code segment, also known as a text segment */ .text : { - *(.text.unlikely .text.*_unlikely .text.unlikely.*) - *(.text.exit .text.exit.*) + PROVIDE( _text = ABSOLUTE(.) ); + /* Initialization code segment */ + KEEP( *(.text.start) ) + *(.text.unlikely .text.unlikely.*) *(.text.startup .text.startup.*) - *(.text.hot .text.hot.*) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } > ram : DATA - - .fini : - { - KEEP (*(SORT_NONE(.fini))) - } > ram : DATA - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } > ram : DATA - .rodata1 : { *(.rodata1) } > ram : DATA - .sdata2 : + /* Normal code segment */ + *(.text .text.*) + *(.gnu.linkonce.t.*) + + . = ALIGN(8); + PROVIDE( _etext = ABSOLUTE(.) ); + } >ram AT>ram :ram_ro + + /* Read-only data segment */ + .rodata : { - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - } > ram : DATA + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } >ram AT>ram :ram_ro + + . = ALIGN(8); + /* Exception handling */ .eh_frame : { KEEP (*(.eh_frame)) *(.eh_frame.*) . = ALIGN(8); - } > ram : DATA - .gnu_extab : { *(.gnu_extab) } > ram : DATA - .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } > ram : DATA - .exception_ranges : { *(.exception_ranges .exception_ranges*) } > ram : DATA - + } >ram AT>ram :ram_ro + .gnu_extab : { *(.gnu_extab) } >ram AT>ram :ram_ro + .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } >ram AT>ram :ram_ro + .exception_ranges : { *(.exception_ranges .exception_ranges*) } >ram AT>ram :ram_ro + + /* Init array and fini array */ .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); - } > ram : DATA + } >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)) + *(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors) PROVIDE_HIDDEN (__init_array_end = .); - } > ram : DATA + } >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 : DATA + } >ram AT>ram :ram_ro .ctors : { @@ -143,7 +146,8 @@ SECTIONS KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) - } > ram : DATA + } >ram AT>ram :ram_ro + .dtors : { KEEP (*crtbegin.o(.dtors)) @@ -151,49 +155,64 @@ SECTIONS KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) - } > ram : DATA - - . = ALIGN(64); - .data : + } >ram AT>ram :ram_ro + + . = ALIGN(8); + + .lalign : { - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } > ram : DATA - .data1 : { *(.data1) } > ram : DATA - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : + . = ALIGN(8); + PROVIDE( _data_lma = . ); + } >ram AT>ram :ram_ro + + .dalign : { - __global_pointer$ = . + 0x800; - *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) - *(.sdata .sdata.* .gnu.linkonce.s.*) - } > ram : DATA - _edata = .; PROVIDE (edata = .); - + . = ALIGN(8); + PROVIDE( _data = . ); + } >ram AT>ram :ram_init + . = ALIGN(8); - . = .; - __bss_start = .; - .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } > ram : DYN_DATA - .sbss : + + /* .data, .sdata and .srodata segment */ + .data : { - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - } > ram : DYN_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( __global_pointer$ = 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 : { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) + 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 here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 64 / 8 : 1); - } > ram : DYN_DATA - __bss_end = .; + + . = ALIGN(8); + PROVIDE( _ebss = ABSOLUTE(.) ); + } >ram AT>ram :ram PROVIDE( _tls_data = ABSOLUTE(.) ); /* @@ -210,7 +229,7 @@ SECTIONS *(.tdata .tdata.*) *(.gnu.linkonce.td.*) KEEP( *(.tdata.end) ) - } > ram : DATA + } >ram AT>ram :ram /* Thread-local bss segment, .tbss (zero-initialized tls). */ .tbss : @@ -218,7 +237,7 @@ SECTIONS *(.tbss .tbss.*) *(.gnu.linkonce.tb.*) KEEP( *(.tbss.end) ) - } > ram : DYN_DATA + } >ram AT>ram :ram /* * End of uninitalized data segement @@ -229,49 +248,18 @@ SECTIONS * Align _heap_start to cache line size */ . = ALIGN(64); - _end = .; PROVIDE( _end = ABSOLUTE(.) ); + PROVIDE( _end = ABSOLUTE(.) ); /* Leave 2 holes for stack & TLS, the size can set in kconfig */ - PROVIDE( _heap_start = ABSOLUTE(.) + _stack_size * 5 ); + + PROVIDE( _heap_start = ABSOLUTE(.) ); + /* 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 ); - - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } } diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_3M.ld b/Kboot/lds/kendryte.ld similarity index 50% rename from k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_3M.ld rename to Kboot/lds/kendryte.ld index b4e6e0f..fc99e70 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_3M.ld +++ b/Kboot/lds/kendryte.ld @@ -3,28 +3,27 @@ * 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. */ - /* - * LoBo: The LENGTH specified here must be enough to run the MicroPython firmware - * including creating all static, global and dynamic variables on K210 heap - */ - - MEMORY { /* * Memory with CPU cache. - * CPU SRAM + * 64K CPU SRAM */ - ram (wxa!ri) : ORIGIN = 0x80002000, LENGTH = (0x300000-0x2000) + ram (wxari) : ORIGIN = 0x805E0000, LENGTH = 0x00008000 /* * Memory without CPU cache - * CPU SRAM + * 64K CPU SRAM */ - ram_nocache (wxa!ri) : ORIGIN = 0x40002000, LENGTH = (0x300000-0x2000) + ram_nocache (wxari) : ORIGIN = 0x405E0000, LENGTH = 0x00008000 } +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( _stack_size = 1 << 16 ); +PROVIDE( _io_start = ORIGIN(ram_nocache) ); +PROVIDE( _io_end = _io_start + LENGTH(ram_nocache) ); + /* * The OUTPUT_ARCH command specifies the machine architecture where the @@ -38,14 +37,25 @@ OUTPUT_ARCH( "riscv" ) */ 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 { - DATA PT_LOAD; - DYN_DATA PT_NULL; + ram_ro PT_LOAD; + ram_init PT_LOAD; + ram PT_NULL; } /* @@ -54,74 +64,65 @@ PHDRS */ SECTIONS { - .text.start : - { - KEEP( *(.text.start) ) - KEEP( *(.text.systick) ) - } > ram : DATA - - .init : - { - KEEP (*(SORT_NONE(.init))) - } > ram : DATA - - . = ALIGN(8); - . = .; + /* Program code segment, also known as a text segment */ .text : { - *(.text.unlikely .text.*_unlikely .text.unlikely.*) - *(.text.exit .text.exit.*) + PROVIDE( _text = ABSOLUTE(.) ); + /* Initialization code segment */ + KEEP( *(.text.start) ) + *(.text.unlikely .text.unlikely.*) *(.text.startup .text.startup.*) - *(.text.hot .text.hot.*) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } > ram : DATA - - .fini : - { - KEEP (*(SORT_NONE(.fini))) - } > ram : DATA - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } > ram : DATA - .rodata1 : { *(.rodata1) } > ram : DATA - .sdata2 : + /* Normal code segment */ + *(.text .text.*) + *(.gnu.linkonce.t.*) + + . = ALIGN(8); + PROVIDE( _etext = ABSOLUTE(.) ); + } >ram AT>ram :ram_ro + + /* Read-only data segment */ + .rodata : { - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - } > ram : DATA + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } >ram AT>ram :ram_ro + + . = ALIGN(8); + /* Exception handling */ .eh_frame : { KEEP (*(.eh_frame)) *(.eh_frame.*) . = ALIGN(8); - } > ram : DATA - .gnu_extab : { *(.gnu_extab) } > ram : DATA - .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } > ram : DATA - .exception_ranges : { *(.exception_ranges .exception_ranges*) } > ram : DATA - + } >ram AT>ram :ram_ro + .gnu_extab : { *(.gnu_extab) } >ram AT>ram :ram_ro + .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } >ram AT>ram :ram_ro + .exception_ranges : { *(.exception_ranges .exception_ranges*) } >ram AT>ram :ram_ro + + /* Init array and fini array */ .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); - } > ram : DATA + } >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)) + *(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors) PROVIDE_HIDDEN (__init_array_end = .); - } > ram : DATA + } >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 : DATA + } >ram AT>ram :ram_ro .ctors : { @@ -143,7 +144,8 @@ SECTIONS KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) - } > ram : DATA + } >ram AT>ram :ram_ro + .dtors : { KEEP (*crtbegin.o(.dtors)) @@ -151,49 +153,64 @@ SECTIONS KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) - } > ram : DATA - - . = ALIGN(64); - .data : + } >ram AT>ram :ram_ro + + . = ALIGN(8); + + .lalign : { - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } > ram : DATA - .data1 : { *(.data1) } > ram : DATA - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : + . = ALIGN(8); + PROVIDE( _data_lma = . ); + } >ram AT>ram :ram_ro + + .dalign : { - __global_pointer$ = . + 0x800; - *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) - *(.sdata .sdata.* .gnu.linkonce.s.*) - } > ram : DATA - _edata = .; PROVIDE (edata = .); - + . = ALIGN(8); + PROVIDE( _data = . ); + } >ram AT>ram :ram_init + . = ALIGN(8); - . = .; - __bss_start = .; - .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } > ram : DYN_DATA - .sbss : + + /* .data, .sdata and .srodata segment */ + .data : { - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - } > ram : DYN_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( __global_pointer$ = 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 : { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) + 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 here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 64 / 8 : 1); - } > ram : DYN_DATA - __bss_end = .; + + . = ALIGN(8); + PROVIDE( _ebss = ABSOLUTE(.) ); + } >ram AT>ram :ram PROVIDE( _tls_data = ABSOLUTE(.) ); /* @@ -210,7 +227,7 @@ SECTIONS *(.tdata .tdata.*) *(.gnu.linkonce.td.*) KEEP( *(.tdata.end) ) - } > ram : DATA + } >ram AT>ram :ram /* Thread-local bss segment, .tbss (zero-initialized tls). */ .tbss : @@ -218,7 +235,7 @@ SECTIONS *(.tbss .tbss.*) *(.gnu.linkonce.tb.*) KEEP( *(.tbss.end) ) - } > ram : DYN_DATA + } >ram AT>ram :ram /* * End of uninitalized data segement @@ -229,49 +246,18 @@ SECTIONS * Align _heap_start to cache line size */ . = ALIGN(64); - _end = .; PROVIDE( _end = ABSOLUTE(.) ); + PROVIDE( _end = ABSOLUTE(.) ); /* Leave 2 holes for stack & TLS, the size can set in kconfig */ - PROVIDE( _heap_start = ABSOLUTE(.) + _stack_size * 5 ); + + PROVIDE( _heap_start = ABSOLUTE(.) ); + /* 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 ); - - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } } diff --git a/Kboot/lib/CMakeLists.txt b/Kboot/lib/CMakeLists.txt new file mode 100644 index 0000000..c2a2e97 --- /dev/null +++ b/Kboot/lib/CMakeLists.txt @@ -0,0 +1,28 @@ +#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}/*.c" + "${CMAKE_CURRENT_LIST_DIR}/*.cpp" + "${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(${SDK_ROOT}/third_party/xtl/include) +include_directories(${CMAKE_CURRENT_LIST_DIR}/drivers/include ${CMAKE_CURRENT_LIST_DIR}/bsp/include ${CMAKE_CURRENT_LIST_DIR}/nncase/include) + +SET_PROPERTY(SOURCE ${ASSEMBLY_FILES} PROPERTY LANGUAGE C) +SET_SOURCE_FILES_PROPERTIES(${ASSEMBLY_FILES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D __riscv64") + +ADD_LIBRARY(kendryte + ${LIB_SRC} + ) +SET_TARGET_PROPERTIES(kendryte PROPERTIES LINKER_LANGUAGE C) diff --git a/Kboot/src/bootloader_hi/README.md b/Kboot/src/bootloader_hi/README.md new file mode 100644 index 0000000..b7e29fc --- /dev/null +++ b/Kboot/src/bootloader_hi/README.md @@ -0,0 +1,205 @@ +# Kboot + +**Kboot** is a small applications (< 8KB) which enables loading and executing applications from any K210 SPI Flash location. + +## Features + +* load and execute K210 application stored on any location in SPI Flash +* application to be loaded is chosen from the list of available applications in **Kboot configuration sector** +* multiple criteria application validity check is performed when selecting the application +* if no valid application is found **default application** is loaded and executed +* The **interactive mode** can be enabled in which,based on the specific **Pin** state, the user can choose which application to load and execute +
+ +## Boot process + +* After reset **Kboot** application is loaded by **K210 ROM** to sram address **`0x80000000`** and executed +* SPI Flash driver is initialized in **XiP** mode +* If allowed by configuration, **Boot Pin** state is checked and saved, if Boot Pin is activated **interactive mode** is enabled +* **Configuration sector** is scanned for valid applications, the following actions are performed: + * Configuration entry ID is checked + * Application Flash address is cheched for valid range + * Application size is checked for valid range + * Application flags are saved + * Application _Flash block_ ***** is checked for valid format + * If **CRC32** flag is set, application's crc32 is calculated and checked + * If **SHA256** flag is set, application's SHA256 hash is calculated and checked +* If all checks passes, the application is marked as **valid** +* If **not in interactive mode**, configuration sector scan is terminated as soon as the first valid, flagged as **active** application is found and that application is loaded and executed +* If in **interactive mode**, all configuration sector entries are scanned and the user is prompted to select which one to load and execute +* If **no valid application** is found, the **default application** is loaded and executed + +> ***** each application stored in SPI Flash has the following format: +> +> | Byte offset | Size | Name | Content | +> | ---: | ---: | :---: | :--- | +> | `0` | `1` | AES_FLAG | AES cipher flag, for use with **Kboot** must be `0` | +> | `1` | `4` | APP_SIZE | EApplication code size | +> | `5` | `APP_SIZE` | APP_CODE | Application code | +> | `APP_SIZE + 5` | `32` | SHA_HASH | Application SHA256 hash | +> +> All applications flashed with **Kflash** have such format. + +
+ +## K210 SPI Flash layout + +The following SPI Flash layout must be used when using **Kboot* + +| From | To | Length | Comment | +| ---: | ---: | ---: | :--- | +| `0x00000000` | `0x0000FFFF` | 64K | **Kboot** application code | +| `0x00010000` | `0x0001FFFF` | 64K | reserved for future use | +| `0x00020000` | `0x00020FFF` | 4K | main **boot configuration** sector | +| `0x00021000` | `0x00021FFF` | 4K | backup **boot configuration** sector | +| `0x00022000` | `0x0002FFFF` | 56K | reserved, user data etc. | +| `0x00030000` | `0x0007FFFF` | 320K | **default application** code | +| `0x00080000` | `Flash end` | --- | user area, application(s) code, file system(s), user data etc. | + +
+ +## **Boot configuration** sector + +Boot configuration used by **Kboot** is stored in one SPI Flash sector (4KB) at fixed Flash address.
+One **backup** configuration sector is also used for security reasons.
+ +The configuration sector consists of **`8`** application entries occupying **`32`** bytes each + 32bit value, the configuration flags.
+ +Configuration sector layout: + +| Offset | To | Length | Comment | +| ---: | ---: | ---: | :--- | +| `0x000` | `01F` | `32` | application entry #0 | +| `0x020` | `03F` | `32` | application entry #1 | +| `0x040` | `05F` | `32` | application entry #2 | +| `0x060` | `07F` | `32` | application entry #3 | +| `0x080` | `09F` | `32` | application entry #4 | +| `0x0A0` | `0BF` | `32` | application entry #5 | +| `0x0C0` | `0DF` | `32` | application entry #6 | +| `0x0E0` | `0FF` | `32` | application entry #7 | +| `0x100` | `103` | `4` | **config flags** | +| `0x104` | `11F` | `4` | reserved | +| `0x120` | `11F` | `4` | not used, user data | +
+ +The format of each application entry in configuration sector is as follows: + +| Offset | Length | Comment | +| ---: | ---: | :--- | +| `0` | `4` | Configuration entry **ID** (bits 4-31) + entry **flags** (bits 0-4) | +| `4` | `4` | Application address in SPI Flash | +| `8` | `4` | Application size in SPI Flash. This is the size of the application's **`.bin`** file | +| `12` | `4` | Application's CRC32 value (32bits) | +| `16` | `16` | Null terminated application name/description | + +_Notes:_
+Configuration entry **ID** must have a value of **`0x5AA5D0C0`** for entry to recognized as valid.
+Application addres must be in range **`0x80000`** ~ **`0x800000`** ( 512KB ~ 8MB ).
+Application size must be in range **`0x4000`** ~ **`0x300000`** ( 16KB ~ 3MB ).
+Application CRC32 value is used only if **CRC32** flag is set.

+ +If **config flags** at offset `0x100` in **configuration sector** is set to configuration entry **ID** (**`0x5AA5D0C0`**), **interractive mode** will be disabled, **boot Pin* and nothing will be printed during the boot process. +Configuration entry **flags**: + +| Bit | Comment | +| :---: | :--- | +| `0` | **Active** flag, if set the application will be loaded and executed.
If multiple entries have **active** flag set, the first one will be loaded ad executed | +| `1` | **CRC32** flag, if set the application's CRC32 value will be calculated and compared with the value in the configuration entry | +| `2` | **AES256** flag, if set the application's AES256 hash value will be calculated and compared with the value stored in flash after the application code (`SHA_HASH`) | +| `3` | Not used, reserved | + +**_Warning:_** all 32-bit values in the configuration sector entries must be written in **big-endian** format. + +
+ +## Default application + +If in the boot process **no valid application** was found in the **configuration sector**, the **default application** is loaded and executed.
+If the **default application** is loaded that usually means some error occured and the system may be considered unusable.
+**_The default application should try to check what was wrong and try to correct the issue._** + +
+ +## Building the applications to be used with _Kboot_ + +Importand thing to remember is that the applications loaded and executed by **Kboot** are **NOT loaded** at the default K210 SRAM address **(`0x80000000`)**, but at address **`0x80002000`** !
+Therefore, when building the application, it must be **linked** for start address **`0x80002000`**.
+ +Fortunatelly, it is quite simple to do it, only a slight modification of the linker script is needed.
+The linker script is usually called **kendryte.ld** and it is located in the **Kendryte SDK** **_lds_** directory.
+The beginning of that file looks like this: +``` +/* + * 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) +} +``` + +The only entries which has to be changed are **`ORIGIN`** and **`LENGTH`**.
+Change:
+`ORIGIN = 0x80000000` to **`ORIGIN = 0x80002000`**
+`ORIGIN = 0x40000000` to **`ORIGIN = 0x40002000`**
+`LENGTH = (6 * 1024 * 1024)` to **`LENGTH = (6 * 1024 * 1024 - 0x2000)`**
+ +and build the application as usual.
+ +The beginning of the modified **kendryte.ld** should look like this: +```console +/* + * 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 = 0x80002000, LENGTH = (6 * 1024 * 1024 - 0x2000) + /* + * Memory without CPU cache + * 6M CPU SRAM + */ + ram_nocache (wxa!ri) : ORIGIN = 0x40002000, LENGTH = (6 * 1024 * 1024 - 0x2000) +} +``` + +**_When building the application also check if any part of the code depends on application start address in SRAM._**
+For most applications it is not the case. + +

+ +## Usage + +Flashing the application(s) to SPI Flash and manipulating the boot **configuration sector** should be performed from the user application.
+Accessing SPI flash from K210 application is quite easy and reliable. + + + +### Example + +**Application firmware update** + +* The condition to update the firmware is detected by the application +* Load the **boot configuration** sector, check its integrity and check the flash address and size of the currently running application +* Flash the new firmware to the **not used** SPI Flash area. The new firmware can be downloaded from remote server using WiFi or GSM, loaded from SD Card, etc ...
Use the **application block** format described above.
The application can be flashed **without** SHA256 hash, in that case do not set the **`SHA256`** flag. +* Calculate new firmware's CRC32 and/or SHA256 hash if needed. +* Flash the current **main** boot configuration sector to the **backup** boot configuration sector and check it.
It will be used by **Kboot** in case the **main** boot configuration sector which we are going to write is corrupted. +* Update (add or change entry) in the boot configuration sector with the new firmware information, set the new firmware as active and the old firmware as inactive and flash the configuration sector. +* Reset (reboot) the system to start the new firmware. + diff --git a/Kboot/src/bootloader_hi/crt.S b/Kboot/src/bootloader_hi/crt.S new file mode 100644 index 0000000..e06e7d7 --- /dev/null +++ b/Kboot/src/bootloader_hi/crt.S @@ -0,0 +1,23 @@ +# Copyright 2019 LoBo (https://github.com/loboris) +# +# 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. + + +.section .text.start, "ax", @progbits +.globl _start +_start: +# Jump directly to 'main' + + j main +.ascii "Kboot_v1.4.1" +.word 0 diff --git a/Kboot/src/bootloader_hi/fpioa.c b/Kboot/src/bootloader_hi/fpioa.c new file mode 100644 index 0000000..1cc8f5d --- /dev/null +++ b/Kboot/src/bootloader_hi/fpioa.c @@ -0,0 +1,4932 @@ +/* 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 +#include +#include "fpioa.h" +#include "sysctl.h" + +volatile fpioa_t *const fpioa = (volatile fpioa_t *)FPIOA_BASE_ADDR; + +/** + * @brief Internal used FPIOA function initialize cell + * + * This is NOT fpioa_io_config_t, can't assign directly + * + */ +typedef struct _fpioa_assign_t +{ + uint32_t ch_sel : 8; + /* Channel select from 256 input. */ + uint32_t ds : 4; + /* Driving selector. */ + uint32_t oe_en : 1; + /* Static output enable, will AND with OE_INV. */ + uint32_t oe_inv : 1; + /* Invert output enable. */ + uint32_t do_sel : 1; + /* Data output select: 0 for DO, 1 for OE. */ + uint32_t do_inv : 1; + /* Invert the result of data output select (DO_SEL). */ + uint32_t pu : 1; + /* Pull up enable. 0 for nothing, 1 for pull up. */ + uint32_t pd : 1; + /* Pull down enable. 0 for nothing, 1 for pull down. */ + uint32_t resv0 : 1; + /* Reserved bits. */ + uint32_t sl : 1; + /* Slew rate control enable. */ + uint32_t ie_en : 1; + /* Static input enable, will AND with IE_INV. */ + uint32_t ie_inv : 1; + /* Invert input enable. */ + uint32_t di_inv : 1; + /* Invert Data input. */ + uint32_t st : 1; + /* Schmitt trigger. */ + uint32_t tie_en : 1; + /* Input tie enable, 1 for enable, 0 for disable. */ + uint32_t tie_val : 1; + /* Input tie value, 1 for high, 0 for low. */ + uint32_t resv1 : 5; + /* Reserved bits. */ + uint32_t pad_di : 1; + /* Read current PAD's data input. */ +} __attribute__((packed, aligned(4))) fpioa_assign_t; + +/* Function list */ +static const fpioa_assign_t function_config[FUNC_MAX] = + { + {.ch_sel = FUNC_JTAG_TCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_JTAG_TDI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_JTAG_TMS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_JTAG_TDO, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_D4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_D5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_D6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_D7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_SS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_SS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_SS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_SS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_ARB, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 1, + .tie_val = 1, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI0_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UARTHS_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UARTHS_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_RESV6, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_RESV7, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CLK_SPI1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CLK_I2C1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS9, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS10, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS11, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS12, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS13, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS15, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS16, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS17, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS18, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS19, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS20, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS21, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS22, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS23, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS24, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS25, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS26, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS27, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS28, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS29, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS30, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIOHS31, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIO0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIO1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIO2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIO3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIO4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIO5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIO6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_GPIO7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_D4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_D5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_D6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_D7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_SS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_SS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_SS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_SS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_ARB, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 1, + .tie_val = 1, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI1_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI_SLAVE_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI_SLAVE_SS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SPI_SLAVE_SCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S0_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S1_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2S2_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_RESV0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_RESV1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_RESV2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_RESV3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_RESV4, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_RESV5, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2C0_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2C0_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2C1_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2C1_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2C2_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_I2C2_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_XCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_RST, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_PWDN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_VSYNC, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_HREF, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_PCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_D4, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_D5, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_D6, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CMOS_D7, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SCCB_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_SCCB_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART1_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART2_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_UART3_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER0_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER0_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER0_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER0_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER1_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER1_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER1_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER1_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER2_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER2_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER2_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_TIMER2_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CLK_SPI2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CLK_I2C2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL9, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL10, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL11, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL12, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL13, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL15, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL16, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL17, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_CONSTANT, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_INTERNAL18, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG9, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG10, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG11, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG12, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG13, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG15, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG16, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG17, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG18, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG19, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG20, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG21, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG22, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG23, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG24, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG25, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG26, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG27, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG28, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG29, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG30, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, + {.ch_sel = FUNC_DEBUG31, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0}, +}; + +int fpioa_init(void) +{ + int i = 0; + + /* Enable fpioa clock in system controller */ + //sysctl_clock_enable(SYSCTL_CLOCK_FPIOA); + + /* Initialize tie */ + fpioa_tie_t tie = {0}; + + /* Set tie enable and tie value */ + for(i = 0; i < FUNC_MAX; i++) + { + tie.en[i / 32] |= (function_config[i].tie_en << (i % 32)); + tie.val[i / 32] |= (function_config[i].tie_val << (i % 32)); + } + + /* Atomic write every 32bit register to fpioa function */ + for(i = 0; i < FUNC_MAX / 32; i++) + { + /* Set value before enable */ + fpioa->tie.val[i] = tie.val[i]; + fpioa->tie.en[i] = tie.en[i]; + } + + return 0; +} + +int fpioa_get_io(int number, fpioa_io_config_t *cfg) +{ + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO || cfg == NULL) + return -1; + /* Atomic read register */ + *cfg = fpioa->io[number]; + return 0; +} + +int fpioa_set_io(int number, fpioa_io_config_t *cfg) +{ + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO || cfg == NULL) + return -1; + /* Atomic write register */ + fpioa->io[number] = *cfg; + return 0; +} + +int fpioa_set_io_pull(int number, fpioa_pull_t pull) +{ + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO || pull >= FPIOA_PULL_MAX) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + + switch(pull) + { + case FPIOA_PULL_NONE: + cfg.pu = 0; + cfg.pd = 0; + break; + case FPIOA_PULL_DOWN: + cfg.pu = 0; + cfg.pd = 1; + break; + case FPIOA_PULL_UP: + cfg.pu = 1; + cfg.pd = 0; + break; + default: + break; + } + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_get_io_pull(int number) +{ + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO) + return -1; + + fpioa_pull_t pull; + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + + if(cfg.pu == 0 && cfg.pd == 1) + pull = FPIOA_PULL_DOWN; + else if(cfg.pu == 1 && cfg.pd == 0) + pull = FPIOA_PULL_UP; + else + pull = FPIOA_PULL_NONE; + return pull; +} + +int fpioa_set_io_driving(int number, fpioa_driving_t driving) +{ + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO || driving >= FPIOA_DRIVING_MAX) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + /* Set IO driving */ + cfg.ds = driving; + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_set_sl(int number, uint8_t sl_enable) +{ + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + /* Set IO slew rate */ + cfg.sl = sl_enable; + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_set_st(int number, uint8_t st_enable) +{ + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + /* Set IO schmitt trigger */ + cfg.st = st_enable; + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_set_oe_inv(int number, uint8_t inv_enable) +{ + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + /* Set IO schmitt trigger */ + cfg.oe_inv = inv_enable; + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_get_io_driving(int number) +{ + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO) + return -1; + + return fpioa->io[number].ds; +} + +int fpioa_set_function_raw(int number, fpioa_function_t function) +{ + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX) + return -1; + /* Atomic write register */ + fpioa->io[number] = (const fpioa_io_config_t){ + .ch_sel = function_config[function].ch_sel, + .ds = function_config[function].ds, + .oe_en = function_config[function].oe_en, + .oe_inv = function_config[function].oe_inv, + .do_sel = function_config[function].do_sel, + .do_inv = function_config[function].do_inv, + .pu = function_config[function].pu, + .pd = function_config[function].pd, + .sl = function_config[function].sl, + .ie_en = function_config[function].ie_en, + .ie_inv = function_config[function].ie_inv, + .di_inv = function_config[function].di_inv, + .st = function_config[function].st, + /* resv and pad_di do not need initialization */ + }; + return 0; +} + +int fpioa_set_function(int number, fpioa_function_t function) +{ + uint8_t index = 0; + /* Check parameters */ + if(number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX) + return -1; + if(function == FUNC_RESV0) + { + fpioa_set_function_raw(number, FUNC_RESV0); + return 0; + } + /* Compare all IO */ + for(index = 0; index < FPIOA_NUM_IO; index++) + { + if((fpioa->io[index].ch_sel == function) && (index != number)) + fpioa_set_function_raw(index, FUNC_RESV0); + } + fpioa_set_function_raw(number, function); + return 0; +} + +int fpioa_set_tie_enable(fpioa_function_t function, int enable) +{ + /* Check parameters */ + if(function < 0 || function >= FUNC_MAX) + return -1; + /* Set tie enable */ + if(enable) + fpioa->tie.en[function / 32] |= (1UL << (function % 32)); + else + fpioa->tie.en[function / 32] &= (~(1UL << (function % 32))); + return 0; +} + +int fpioa_set_tie_value(fpioa_function_t function, int value) +{ + /* Check parameters */ + if(function < 0 || function >= FUNC_MAX) + return -1; + /* Set tie value */ + if(value) + fpioa->tie.val[function / 32] |= (1UL << (function % 32)); + else + fpioa->tie.val[function / 32] &= (~(1UL << (function % 32))); + return 0; +} + +int fpioa_get_io_by_function(fpioa_function_t function) +{ + int index = 0; + for(index = 0; index < FPIOA_NUM_IO; index++) + { + if(fpioa->io[index].ch_sel == function) + return index; + } + + return -1; +} diff --git a/Kboot/src/bootloader_hi/gpiohs.c b/Kboot/src/bootloader_hi/gpiohs.c new file mode 100644 index 0000000..273e23b --- /dev/null +++ b/Kboot/src/bootloader_hi/gpiohs.c @@ -0,0 +1,110 @@ +/* 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.h" +#include "gpiohs.h" +#include "sysctl.h" + +#define GPIOHS_MAX_PINNO 32 + +volatile gpiohs_t *const gpiohs = (volatile gpiohs_t *)GPIOHS_BASE_ADDR; + +/* +typedef struct _gpiohs_pin_instance +{ + size_t pin; + gpio_pin_edge_t edge; + void (*callback)(); + //plic_irq_callback_t gpiohs_callback; + void *context; +} gpiohs_pin_instance_t; + +static gpiohs_pin_instance_t pin_instance[32]; +*/ + +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 gpiohs_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode) +{ + int io_number = fpioa_get_io_by_function(FUNC_GPIOHS0 + pin); + + fpioa_pull_t pull = FPIOA_PULL_NONE; + uint32_t dir = 0; + + switch(mode) + { + case GPIO_DM_INPUT: + pull = FPIOA_PULL_NONE; + dir = 0; + break; + case GPIO_DM_INPUT_PULL_DOWN: + pull = FPIOA_PULL_DOWN; + dir = 0; + break; + case GPIO_DM_INPUT_PULL_UP: + pull = FPIOA_PULL_UP; + dir = 0; + break; + case GPIO_DM_OUTPUT: + pull = FPIOA_PULL_DOWN; + dir = 1; + break; + default: + break; + } + + fpioa_set_io_pull(io_number, pull); + volatile uint32_t *reg = dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32; + volatile uint32_t *reg_d = !dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32; + set_gpio_bit(reg_d, pin, 0); + set_gpio_bit(reg, pin, 1); +} + +gpio_pin_value_t gpiohs_get_pin(uint8_t pin) +{ + return get_gpio_bit(gpiohs->input_val.u32, pin); +} + +void gpiohs_set_pin(uint8_t pin, gpio_pin_value_t value) +{ + set_gpio_bit(gpiohs->output_val.u32, pin, value); +} + diff --git a/Kboot/src/bootloader_hi/include/config.h b/Kboot/src/bootloader_hi/include/config.h new file mode 100644 index 0000000..70f2301 --- /dev/null +++ b/Kboot/src/bootloader_hi/include/config.h @@ -0,0 +1,6 @@ +/* + * Defined from MicroPython build + */ +#define FIRMWARE_SIZE (0x300000UL) +#define BOOT_PIN -1 + diff --git a/Kboot/src/bootloader_hi/include/encoding.h b/Kboot/src/bootloader_hi/include/encoding.h new file mode 100644 index 0000000..3eebee5 --- /dev/null +++ b/Kboot/src/bootloader_hi/include/encoding.h @@ -0,0 +1,1325 @@ +/* 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 RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define MSTATUS_UIE 0x00000001U +#define MSTATUS_SIE 0x00000002U +#define MSTATUS_HIE 0x00000004U +#define MSTATUS_MIE 0x00000008U +#define MSTATUS_UPIE 0x00000010U +#define MSTATUS_SPIE 0x00000020U +#define MSTATUS_HPIE 0x00000040U +#define MSTATUS_MPIE 0x00000080U +#define MSTATUS_SPP 0x00000100U +#define MSTATUS_HPP 0x00000600U +#define MSTATUS_MPP 0x00001800U +#define MSTATUS_FS 0x00006000U +#define MSTATUS_XS 0x00018000U +#define MSTATUS_MPRV 0x00020000U +#define MSTATUS_PUM 0x00040000U +#define MSTATUS_MXR 0x00080000U +#define MSTATUS_VM 0x1F000000U +#define MSTATUS32_SD 0x80000000U +#define MSTATUS64_SD 0x8000000000000000U + +#define SSTATUS_UIE 0x00000001U +#define SSTATUS_SIE 0x00000002U +#define SSTATUS_UPIE 0x00000010U +#define SSTATUS_SPIE 0x00000020U +#define SSTATUS_SPP 0x00000100U +#define SSTATUS_FS 0x00006000U +#define SSTATUS_XS 0x00018000U +#define SSTATUS_PUM 0x00040000U +#define SSTATUS32_SD 0x80000000U +#define SSTATUS64_SD 0x8000000000000000U + +#define DCSR_XDEBUGVER (3U << 30) +#define DCSR_NDRESET (1U << 29) +#define DCSR_FULLRESET (1U << 28) +#define DCSR_EBREAKM (1U << 15) +#define DCSR_EBREAKH (1U << 14) +#define DCSR_EBREAKS (1U << 13) +#define DCSR_EBREAKU (1U << 12) +#define DCSR_STOPCYCLE (1U << 10) +#define DCSR_STOPTIME (1U << 9) +#define DCSR_CAUSE (7U << 6) +#define DCSR_DEBUGINT (1U << 5) +#define DCSR_HALT (1U << 3) +#define DCSR_STEP (1U << 2) +#define DCSR_PRV (3U << 0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_SELECT (1U << 19) +#define MCONTROL_TIMING (1U << 18) +#define MCONTROL_ACTION (0x3fU << 12) +#define MCONTROL_CHAIN (1U << 11) +#define MCONTROL_MATCH (0xfU << 7) +#define MCONTROL_M (1U << 6) +#define MCONTROL_H (1U << 5) +#define MCONTROL_S (1U << 4) +#define MCONTROL_U (1U << 3) +#define MCONTROL_EXECUTE (1U << 2) +#define MCONTROL_STORE (1U << 1) +#define MCONTROL_LOAD (1U << 0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1U << IRQ_S_SOFT) +#define MIP_HSIP (1U << IRQ_H_SOFT) +#define MIP_MSIP (1U << IRQ_M_SOFT) +#define MIP_STIP (1U << IRQ_S_TIMER) +#define MIP_HTIP (1U << IRQ_H_TIMER) +#define MIP_MTIP (1U << IRQ_M_TIMER) +#define MIP_SEIP (1U << IRQ_S_EXT) +#define MIP_HEIP (1U << IRQ_H_EXT) +#define MIP_MEIP (1U << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define VM_MBARE 0 +#define VM_MBB 1 +#define VM_MBBID 2 +#define VM_SV32 8 +#define VM_SV39 9 +#define VM_SV48 10 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000U +#define DEFAULT_NMIVEC 0x00001004U +#define DEFAULT_MTVEC 0x00001010U +#define CONFIG_STRING_ADDR 0x0000100CU +#define EXT_IO_BASE 0x40000000U +#define DRAM_BASE 0x80000000U + +/* page table entry (PTE) fields */ +#define PTE_V 0x001U /* Valid */ +#define PTE_R 0x002U /* Read */ +#define PTE_W 0x004U /* Write */ +#define PTE_X 0x008U /* Execute */ +#define PTE_U 0x010U /* User */ +#define PTE_G 0x020U /* Global */ +#define PTE_A 0x040U /* Accessed */ +#define PTE_D 0x080U /* Dirty */ +#define PTE_SOFT 0x300U /* Reserved for Software */ + +#define PTE_PPN_SHIFT 10 + +#define MCONTROL_TYPE(xlen) (0xfULL << ((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL << ((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL << ((xlen)-11)) + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#if defined(__riscv) + +#if defined(__riscv64) +#define MSTATUS_SD MSTATUS64_SD +#define SSTATUS_SD SSTATUS64_SD +#define RISCV_PGLEVEL_BITS 9 +#else +#define MSTATUS_SD MSTATUS32_SD +#define SSTATUS_SD SSTATUS32_SD +#define RISCV_PGLEVEL_BITS 10 +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#if defined(__GNUC__) + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ + else \ + asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \ + else \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define read_time() read_csr(mtime) +#define read_cycle() read_csr(mcycle) +#define current_coreid() read_csr(mhartid) + +#endif + +#endif + +#endif + +#endif + +#ifndef RISCV_ENCODING_H +#define RISCV_ENCODING_H +#define MATCH_BEQ 0x63U +#define MASK_BEQ 0x707fU +#define MATCH_BNE 0x1063U +#define MASK_BNE 0x707fU +#define MATCH_BLT 0x4063U +#define MASK_BLT 0x707fU +#define MATCH_BGE 0x5063U +#define MASK_BGE 0x707fU +#define MATCH_BLTU 0x6063U +#define MASK_BLTU 0x707fU +#define MATCH_BGEU 0x7063U +#define MASK_BGEU 0x707fU +#define MATCH_JALR 0x67U +#define MASK_JALR 0x707fU +#define MATCH_JAL 0x6fU +#define MASK_JAL 0x7fU +#define MATCH_LUI 0x37U +#define MASK_LUI 0x7fU +#define MATCH_AUIPC 0x17U +#define MASK_AUIPC 0x7fU +#define MATCH_ADDI 0x13U +#define MASK_ADDI 0x707fU +#define MATCH_SLLI 0x1013U +#define MASK_SLLI 0xfc00707fU +#define MATCH_SLTI 0x2013U +#define MASK_SLTI 0x707fU +#define MATCH_SLTIU 0x3013U +#define MASK_SLTIU 0x707fU +#define MATCH_XORI 0x4013U +#define MASK_XORI 0x707fU +#define MATCH_SRLI 0x5013U +#define MASK_SRLI 0xfc00707fU +#define MATCH_SRAI 0x40005013U +#define MASK_SRAI 0xfc00707fU +#define MATCH_ORI 0x6013U +#define MASK_ORI 0x707fU +#define MATCH_ANDI 0x7013U +#define MASK_ANDI 0x707fU +#define MATCH_ADD 0x33U +#define MASK_ADD 0xfe00707fU +#define MATCH_SUB 0x40000033U +#define MASK_SUB 0xfe00707fU +#define MATCH_SLL 0x1033U +#define MASK_SLL 0xfe00707fU +#define MATCH_SLT 0x2033U +#define MASK_SLT 0xfe00707fU +#define MATCH_SLTU 0x3033U +#define MASK_SLTU 0xfe00707fU +#define MATCH_XOR 0x4033U +#define MASK_XOR 0xfe00707fU +#define MATCH_SRL 0x5033U +#define MASK_SRL 0xfe00707fU +#define MATCH_SRA 0x40005033U +#define MASK_SRA 0xfe00707fU +#define MATCH_OR 0x6033U +#define MASK_OR 0xfe00707fU +#define MATCH_AND 0x7033U +#define MASK_AND 0xfe00707fU +#define MATCH_ADDIW 0x1bU +#define MASK_ADDIW 0x707fU +#define MATCH_SLLIW 0x101bU +#define MASK_SLLIW 0xfe00707fU +#define MATCH_SRLIW 0x501bU +#define MASK_SRLIW 0xfe00707fU +#define MATCH_SRAIW 0x4000501bU +#define MASK_SRAIW 0xfe00707fU +#define MATCH_ADDW 0x3bU +#define MASK_ADDW 0xfe00707fU +#define MATCH_SUBW 0x4000003bU +#define MASK_SUBW 0xfe00707fU +#define MATCH_SLLW 0x103bU +#define MASK_SLLW 0xfe00707fU +#define MATCH_SRLW 0x503bU +#define MASK_SRLW 0xfe00707fU +#define MATCH_SRAW 0x4000503bU +#define MASK_SRAW 0xfe00707fU +#define MATCH_LB 0x3U +#define MASK_LB 0x707fU +#define MATCH_LH 0x1003U +#define MASK_LH 0x707fU +#define MATCH_LW 0x2003U +#define MASK_LW 0x707fU +#define MATCH_LD 0x3003U +#define MASK_LD 0x707fU +#define MATCH_LBU 0x4003U +#define MASK_LBU 0x707fU +#define MATCH_LHU 0x5003U +#define MASK_LHU 0x707fU +#define MATCH_LWU 0x6003U +#define MASK_LWU 0x707fU +#define MATCH_SB 0x23U +#define MASK_SB 0x707fU +#define MATCH_SH 0x1023U +#define MASK_SH 0x707fU +#define MATCH_SW 0x2023U +#define MASK_SW 0x707fU +#define MATCH_SD 0x3023U +#define MASK_SD 0x707fU +#define MATCH_FENCE 0xfU +#define MASK_FENCE 0x707fU +#define MATCH_FENCE_I 0x100fU +#define MASK_FENCE_I 0x707fU +#define MATCH_MUL 0x2000033U +#define MASK_MUL 0xfe00707fU +#define MATCH_MULH 0x2001033U +#define MASK_MULH 0xfe00707fU +#define MATCH_MULHSU 0x2002033U +#define MASK_MULHSU 0xfe00707fU +#define MATCH_MULHU 0x2003033U +#define MASK_MULHU 0xfe00707fU +#define MATCH_DIV 0x2004033U +#define MASK_DIV 0xfe00707fU +#define MATCH_DIVU 0x2005033U +#define MASK_DIVU 0xfe00707fU +#define MATCH_REM 0x2006033U +#define MASK_REM 0xfe00707fU +#define MATCH_REMU 0x2007033U +#define MASK_REMU 0xfe00707fU +#define MATCH_MULW 0x200003bU +#define MASK_MULW 0xfe00707fU +#define MATCH_DIVW 0x200403bU +#define MASK_DIVW 0xfe00707fU +#define MATCH_DIVUW 0x200503bU +#define MASK_DIVUW 0xfe00707fU +#define MATCH_REMW 0x200603bU +#define MASK_REMW 0xfe00707fU +#define MATCH_REMUW 0x200703bU +#define MASK_REMUW 0xfe00707fU +#define MATCH_AMOADD_W 0x202fU +#define MASK_AMOADD_W 0xf800707fU +#define MATCH_AMOXOR_W 0x2000202fU +#define MASK_AMOXOR_W 0xf800707fU +#define MATCH_AMOOR_W 0x4000202fU +#define MASK_AMOOR_W 0xf800707fU +#define MATCH_AMOAND_W 0x6000202fU +#define MASK_AMOAND_W 0xf800707fU +#define MATCH_AMOMIN_W 0x8000202fU +#define MASK_AMOMIN_W 0xf800707fU +#define MATCH_AMOMAX_W 0xa000202fU +#define MASK_AMOMAX_W 0xf800707fU +#define MATCH_AMOMINU_W 0xc000202fU +#define MASK_AMOMINU_W 0xf800707fU +#define MATCH_AMOMAXU_W 0xe000202fU +#define MASK_AMOMAXU_W 0xf800707fU +#define MATCH_AMOSWAP_W 0x800202fU +#define MASK_AMOSWAP_W 0xf800707fU +#define MATCH_LR_W 0x1000202fU +#define MASK_LR_W 0xf9f0707fU +#define MATCH_SC_W 0x1800202fU +#define MASK_SC_W 0xf800707fU +#define MATCH_AMOADD_D 0x302fU +#define MASK_AMOADD_D 0xf800707fU +#define MATCH_AMOXOR_D 0x2000302fU +#define MASK_AMOXOR_D 0xf800707fU +#define MATCH_AMOOR_D 0x4000302fU +#define MASK_AMOOR_D 0xf800707fU +#define MATCH_AMOAND_D 0x6000302fU +#define MASK_AMOAND_D 0xf800707fU +#define MATCH_AMOMIN_D 0x8000302fU +#define MASK_AMOMIN_D 0xf800707fU +#define MATCH_AMOMAX_D 0xa000302fU +#define MASK_AMOMAX_D 0xf800707fU +#define MATCH_AMOMINU_D 0xc000302fU +#define MASK_AMOMINU_D 0xf800707fU +#define MATCH_AMOMAXU_D 0xe000302fU +#define MASK_AMOMAXU_D 0xf800707fU +#define MATCH_AMOSWAP_D 0x800302fU +#define MASK_AMOSWAP_D 0xf800707fU +#define MATCH_LR_D 0x1000302fU +#define MASK_LR_D 0xf9f0707fU +#define MATCH_SC_D 0x1800302fU +#define MASK_SC_D 0xf800707fU +#define MATCH_ECALL 0x73U +#define MASK_ECALL 0xffffffffU +#define MATCH_EBREAK 0x100073U +#define MASK_EBREAK 0xffffffffU +#define MATCH_URET 0x200073U +#define MASK_URET 0xffffffffU +#define MATCH_SRET 0x10200073U +#define MASK_SRET 0xffffffffU +#define MATCH_HRET 0x20200073U +#define MASK_HRET 0xffffffffU +#define MATCH_MRET 0x30200073U +#define MASK_MRET 0xffffffffU +#define MATCH_DRET 0x7b200073U +#define MASK_DRET 0xffffffffU +#define MATCH_SFENCE_VM 0x10400073U +#define MASK_SFENCE_VM 0xfff07fffU +#define MATCH_WFI 0x10500073U +#define MASK_WFI 0xffffffffU +#define MATCH_CSRRW 0x1073U +#define MASK_CSRRW 0x707fU +#define MATCH_CSRRS 0x2073U +#define MASK_CSRRS 0x707fU +#define MATCH_CSRRC 0x3073U +#define MASK_CSRRC 0x707fU +#define MATCH_CSRRWI 0x5073U +#define MASK_CSRRWI 0x707fU +#define MATCH_CSRRSI 0x6073U +#define MASK_CSRRSI 0x707fU +#define MATCH_CSRRCI 0x7073U +#define MASK_CSRRCI 0x707fU +#define MATCH_FADD_S 0x53U +#define MASK_FADD_S 0xfe00007fU +#define MATCH_FSUB_S 0x8000053U +#define MASK_FSUB_S 0xfe00007fU +#define MATCH_FMUL_S 0x10000053U +#define MASK_FMUL_S 0xfe00007fU +#define MATCH_FDIV_S 0x18000053U +#define MASK_FDIV_S 0xfe00007fU +#define MATCH_FSGNJ_S 0x20000053U +#define MASK_FSGNJ_S 0xfe00707fU +#define MATCH_FSGNJN_S 0x20001053U +#define MASK_FSGNJN_S 0xfe00707fU +#define MATCH_FSGNJX_S 0x20002053U +#define MASK_FSGNJX_S 0xfe00707fU +#define MATCH_FMIN_S 0x28000053U +#define MASK_FMIN_S 0xfe00707fU +#define MATCH_FMAX_S 0x28001053U +#define MASK_FMAX_S 0xfe00707fU +#define MATCH_FSQRT_S 0x58000053U +#define MASK_FSQRT_S 0xfff0007fU +#define MATCH_FADD_D 0x2000053U +#define MASK_FADD_D 0xfe00007fU +#define MATCH_FSUB_D 0xa000053U +#define MASK_FSUB_D 0xfe00007fU +#define MATCH_FMUL_D 0x12000053U +#define MASK_FMUL_D 0xfe00007fU +#define MATCH_FDIV_D 0x1a000053U +#define MASK_FDIV_D 0xfe00007fU +#define MATCH_FSGNJ_D 0x22000053U +#define MASK_FSGNJ_D 0xfe00707fU +#define MATCH_FSGNJN_D 0x22001053U +#define MASK_FSGNJN_D 0xfe00707fU +#define MATCH_FSGNJX_D 0x22002053U +#define MASK_FSGNJX_D 0xfe00707fU +#define MATCH_FMIN_D 0x2a000053U +#define MASK_FMIN_D 0xfe00707fU +#define MATCH_FMAX_D 0x2a001053U +#define MASK_FMAX_D 0xfe00707fU +#define MATCH_FCVT_S_D 0x40100053U +#define MASK_FCVT_S_D 0xfff0007fU +#define MATCH_FCVT_D_S 0x42000053U +#define MASK_FCVT_D_S 0xfff0007fU +#define MATCH_FSQRT_D 0x5a000053U +#define MASK_FSQRT_D 0xfff0007fU +#define MATCH_FLE_S 0xa0000053U +#define MASK_FLE_S 0xfe00707fU +#define MATCH_FLT_S 0xa0001053U +#define MASK_FLT_S 0xfe00707fU +#define MATCH_FEQ_S 0xa0002053U +#define MASK_FEQ_S 0xfe00707fU +#define MATCH_FLE_D 0xa2000053U +#define MASK_FLE_D 0xfe00707fU +#define MATCH_FLT_D 0xa2001053U +#define MASK_FLT_D 0xfe00707fU +#define MATCH_FEQ_D 0xa2002053U +#define MASK_FEQ_D 0xfe00707fU +#define MATCH_FCVT_W_S 0xc0000053U +#define MASK_FCVT_W_S 0xfff0007fU +#define MATCH_FCVT_WU_S 0xc0100053U +#define MASK_FCVT_WU_S 0xfff0007fU +#define MATCH_FCVT_L_S 0xc0200053U +#define MASK_FCVT_L_S 0xfff0007fU +#define MATCH_FCVT_LU_S 0xc0300053U +#define MASK_FCVT_LU_S 0xfff0007fU +#define MATCH_FMV_X_S 0xe0000053U +#define MASK_FMV_X_S 0xfff0707fU +#define MATCH_FCLASS_S 0xe0001053U +#define MASK_FCLASS_S 0xfff0707fU +#define MATCH_FCVT_W_D 0xc2000053U +#define MASK_FCVT_W_D 0xfff0007fU +#define MATCH_FCVT_WU_D 0xc2100053U +#define MASK_FCVT_WU_D 0xfff0007fU +#define MATCH_FCVT_L_D 0xc2200053U +#define MASK_FCVT_L_D 0xfff0007fU +#define MATCH_FCVT_LU_D 0xc2300053U +#define MASK_FCVT_LU_D 0xfff0007fU +#define MATCH_FMV_X_D 0xe2000053U +#define MASK_FMV_X_D 0xfff0707fU +#define MATCH_FCLASS_D 0xe2001053U +#define MASK_FCLASS_D 0xfff0707fU +#define MATCH_FCVT_S_W 0xd0000053U +#define MASK_FCVT_S_W 0xfff0007fU +#define MATCH_FCVT_S_WU 0xd0100053U +#define MASK_FCVT_S_WU 0xfff0007fU +#define MATCH_FCVT_S_L 0xd0200053U +#define MASK_FCVT_S_L 0xfff0007fU +#define MATCH_FCVT_S_LU 0xd0300053U +#define MASK_FCVT_S_LU 0xfff0007fU +#define MATCH_FMV_S_X 0xf0000053U +#define MASK_FMV_S_X 0xfff0707fU +#define MATCH_FCVT_D_W 0xd2000053U +#define MASK_FCVT_D_W 0xfff0007fU +#define MATCH_FCVT_D_WU 0xd2100053U +#define MASK_FCVT_D_WU 0xfff0007fU +#define MATCH_FCVT_D_L 0xd2200053U +#define MASK_FCVT_D_L 0xfff0007fU +#define MATCH_FCVT_D_LU 0xd2300053U +#define MASK_FCVT_D_LU 0xfff0007fU +#define MATCH_FMV_D_X 0xf2000053U +#define MASK_FMV_D_X 0xfff0707fU +#define MATCH_FLW 0x2007U +#define MASK_FLW 0x707fU +#define MATCH_FLD 0x3007U +#define MASK_FLD 0x707fU +#define MATCH_FSW 0x2027U +#define MASK_FSW 0x707fU +#define MATCH_FSD 0x3027U +#define MASK_FSD 0x707fU +#define MATCH_FMADD_S 0x43U +#define MASK_FMADD_S 0x600007fU +#define MATCH_FMSUB_S 0x47U +#define MASK_FMSUB_S 0x600007fU +#define MATCH_FNMSUB_S 0x4bU +#define MASK_FNMSUB_S 0x600007fU +#define MATCH_FNMADD_S 0x4fU +#define MASK_FNMADD_S 0x600007fU +#define MATCH_FMADD_D 0x2000043U +#define MASK_FMADD_D 0x600007fU +#define MATCH_FMSUB_D 0x2000047U +#define MASK_FMSUB_D 0x600007fU +#define MATCH_FNMSUB_D 0x200004bU +#define MASK_FNMSUB_D 0x600007fU +#define MATCH_FNMADD_D 0x200004fU +#define MASK_FNMADD_D 0x600007fU +#define MATCH_C_NOP 0x1U +#define MASK_C_NOP 0xffffU +#define MATCH_C_ADDI16SP 0x6101U +#define MASK_C_ADDI16SP 0xef83U +#define MATCH_C_JR 0x8002U +#define MASK_C_JR 0xf07fU +#define MATCH_C_JALR 0x9002U +#define MASK_C_JALR 0xf07fU +#define MATCH_C_EBREAK 0x9002U +#define MASK_C_EBREAK 0xffffU +#define MATCH_C_LD 0x6000U +#define MASK_C_LD 0xe003U +#define MATCH_C_SD 0xe000U +#define MASK_C_SD 0xe003U +#define MATCH_C_ADDIW 0x2001U +#define MASK_C_ADDIW 0xe003U +#define MATCH_C_LDSP 0x6002U +#define MASK_C_LDSP 0xe003U +#define MATCH_C_SDSP 0xe002U +#define MASK_C_SDSP 0xe003U +#define MATCH_C_ADDI4SPN 0x0U +#define MASK_C_ADDI4SPN 0xe003U +#define MATCH_C_FLD 0x2000U +#define MASK_C_FLD 0xe003U +#define MATCH_C_LW 0x4000U +#define MASK_C_LW 0xe003U +#define MATCH_C_FLW 0x6000U +#define MASK_C_FLW 0xe003U +#define MATCH_C_FSD 0xa000U +#define MASK_C_FSD 0xe003U +#define MATCH_C_SW 0xc000U +#define MASK_C_SW 0xe003U +#define MATCH_C_FSW 0xe000U +#define MASK_C_FSW 0xe003U +#define MATCH_C_ADDI 0x1U +#define MASK_C_ADDI 0xe003U +#define MATCH_C_JAL 0x2001U +#define MASK_C_JAL 0xe003U +#define MATCH_C_LI 0x4001U +#define MASK_C_LI 0xe003U +#define MATCH_C_LUI 0x6001U +#define MASK_C_LUI 0xe003U +#define MATCH_C_SRLI 0x8001U +#define MASK_C_SRLI 0xec03U +#define MATCH_C_SRAI 0x8401U +#define MASK_C_SRAI 0xec03U +#define MATCH_C_ANDI 0x8801U +#define MASK_C_ANDI 0xec03U +#define MATCH_C_SUB 0x8c01U +#define MASK_C_SUB 0xfc63U +#define MATCH_C_XOR 0x8c21U +#define MASK_C_XOR 0xfc63U +#define MATCH_C_OR 0x8c41U +#define MASK_C_OR 0xfc63U +#define MATCH_C_AND 0x8c61U +#define MASK_C_AND 0xfc63U +#define MATCH_C_SUBW 0x9c01U +#define MASK_C_SUBW 0xfc63U +#define MATCH_C_ADDW 0x9c21U +#define MASK_C_ADDW 0xfc63U +#define MATCH_C_J 0xa001U +#define MASK_C_J 0xe003U +#define MATCH_C_BEQZ 0xc001U +#define MASK_C_BEQZ 0xe003U +#define MATCH_C_BNEZ 0xe001U +#define MASK_C_BNEZ 0xe003U +#define MATCH_C_SLLI 0x2U +#define MASK_C_SLLI 0xe003U +#define MATCH_C_FLDSP 0x2002U +#define MASK_C_FLDSP 0xe003U +#define MATCH_C_LWSP 0x4002U +#define MASK_C_LWSP 0xe003U +#define MATCH_C_FLWSP 0x6002U +#define MASK_C_FLWSP 0xe003U +#define MATCH_C_MV 0x8002U +#define MASK_C_MV 0xf003U +#define MATCH_C_ADD 0x9002U +#define MASK_C_ADD 0xf003U +#define MATCH_C_FSDSP 0xa002U +#define MASK_C_FSDSP 0xe003U +#define MATCH_C_SWSP 0xc002U +#define MASK_C_SWSP 0xe003U +#define MATCH_C_FSWSP 0xe002U +#define MASK_C_FSWSP 0xe003U +#define MATCH_CUSTOM0 0xbU +#define MASK_CUSTOM0 0x707fU +#define MATCH_CUSTOM0_RS1 0x200bU +#define MASK_CUSTOM0_RS1 0x707fU +#define MATCH_CUSTOM0_RS1_RS2 0x300bU +#define MASK_CUSTOM0_RS1_RS2 0x707fU +#define MATCH_CUSTOM0_RD 0x400bU +#define MASK_CUSTOM0_RD 0x707fU +#define MATCH_CUSTOM0_RD_RS1 0x600bU +#define MASK_CUSTOM0_RD_RS1 0x707fU +#define MATCH_CUSTOM0_RD_RS1_RS2 0x700bU +#define MASK_CUSTOM0_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM1 0x2bU +#define MASK_CUSTOM1 0x707fU +#define MATCH_CUSTOM1_RS1 0x202bU +#define MASK_CUSTOM1_RS1 0x707fU +#define MATCH_CUSTOM1_RS1_RS2 0x302bU +#define MASK_CUSTOM1_RS1_RS2 0x707fU +#define MATCH_CUSTOM1_RD 0x402bU +#define MASK_CUSTOM1_RD 0x707fU +#define MATCH_CUSTOM1_RD_RS1 0x602bU +#define MASK_CUSTOM1_RD_RS1 0x707fU +#define MATCH_CUSTOM1_RD_RS1_RS2 0x702bU +#define MASK_CUSTOM1_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM2 0x5bU +#define MASK_CUSTOM2 0x707fU +#define MATCH_CUSTOM2_RS1 0x205bU +#define MASK_CUSTOM2_RS1 0x707fU +#define MATCH_CUSTOM2_RS1_RS2 0x305bU +#define MASK_CUSTOM2_RS1_RS2 0x707fU +#define MATCH_CUSTOM2_RD 0x405bU +#define MASK_CUSTOM2_RD 0x707fU +#define MATCH_CUSTOM2_RD_RS1 0x605bU +#define MASK_CUSTOM2_RD_RS1 0x707fU +#define MATCH_CUSTOM2_RD_RS1_RS2 0x705bU +#define MASK_CUSTOM2_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM3 0x7bU +#define MASK_CUSTOM3 0x707fU +#define MATCH_CUSTOM3_RS1 0x207bU +#define MASK_CUSTOM3_RS1 0x707fU +#define MATCH_CUSTOM3_RS1_RS2 0x307bU +#define MASK_CUSTOM3_RS1_RS2 0x707fU +#define MATCH_CUSTOM3_RD 0x407bU +#define MASK_CUSTOM3_RD 0x707fU +#define MATCH_CUSTOM3_RD_RS1 0x607bU +#define MASK_CUSTOM3_RD_RS1 0x707fU +#define MATCH_CUSTOM3_RD_RS1_RS2 0x707bU +#define MASK_CUSTOM3_RD_RS1_RS2 0x707fU +#define CSR_FFLAGS 0x1U +#define CSR_FRM 0x2U +#define CSR_FCSR 0x3U +#define CSR_CYCLE 0xc00U +#define CSR_TIME 0xc01U +#define CSR_INSTRET 0xc02U +#define CSR_HPMCOUNTER3 0xc03U +#define CSR_HPMCOUNTER4 0xc04U +#define CSR_HPMCOUNTER5 0xc05U +#define CSR_HPMCOUNTER6 0xc06U +#define CSR_HPMCOUNTER7 0xc07U +#define CSR_HPMCOUNTER8 0xc08U +#define CSR_HPMCOUNTER9 0xc09U +#define CSR_HPMCOUNTER10 0xc0aU +#define CSR_HPMCOUNTER11 0xc0bU +#define CSR_HPMCOUNTER12 0xc0cU +#define CSR_HPMCOUNTER13 0xc0dU +#define CSR_HPMCOUNTER14 0xc0eU +#define CSR_HPMCOUNTER15 0xc0fU +#define CSR_HPMCOUNTER16 0xc10U +#define CSR_HPMCOUNTER17 0xc11U +#define CSR_HPMCOUNTER18 0xc12U +#define CSR_HPMCOUNTER19 0xc13U +#define CSR_HPMCOUNTER20 0xc14U +#define CSR_HPMCOUNTER21 0xc15U +#define CSR_HPMCOUNTER22 0xc16U +#define CSR_HPMCOUNTER23 0xc17U +#define CSR_HPMCOUNTER24 0xc18U +#define CSR_HPMCOUNTER25 0xc19U +#define CSR_HPMCOUNTER26 0xc1aU +#define CSR_HPMCOUNTER27 0xc1bU +#define CSR_HPMCOUNTER28 0xc1cU +#define CSR_HPMCOUNTER29 0xc1dU +#define CSR_HPMCOUNTER30 0xc1eU +#define CSR_HPMCOUNTER31 0xc1fU +#define CSR_SSTATUS 0x100U +#define CSR_SIE 0x104U +#define CSR_STVEC 0x105U +#define CSR_SSCRATCH 0x140U +#define CSR_SEPC 0x141U +#define CSR_SCAUSE 0x142U +#define CSR_SBADADDR 0x143U +#define CSR_SIP 0x144U +#define CSR_SPTBR 0x180U +#define CSR_MSTATUS 0x300U +#define CSR_MISA 0x301U +#define CSR_MEDELEG 0x302U +#define CSR_MIDELEG 0x303U +#define CSR_MIE 0x304U +#define CSR_MTVEC 0x305U +#define CSR_MSCRATCH 0x340U +#define CSR_MEPC 0x341U +#define CSR_MCAUSE 0x342U +#define CSR_MBADADDR 0x343U +#define CSR_MIP 0x344U +#define CSR_TSELECT 0x7a0U +#define CSR_TDATA1 0x7a1U +#define CSR_TDATA2 0x7a2U +#define CSR_TDATA3 0x7a3U +#define CSR_DCSR 0x7b0U +#define CSR_DPC 0x7b1U +#define CSR_DSCRATCH 0x7b2U +#define CSR_MCYCLE 0xb00U +#define CSR_MINSTRET 0xb02U +#define CSR_MHPMCOUNTER3 0xb03U +#define CSR_MHPMCOUNTER4 0xb04U +#define CSR_MHPMCOUNTER5 0xb05U +#define CSR_MHPMCOUNTER6 0xb06U +#define CSR_MHPMCOUNTER7 0xb07U +#define CSR_MHPMCOUNTER8 0xb08U +#define CSR_MHPMCOUNTER9 0xb09U +#define CSR_MHPMCOUNTER10 0xb0aU +#define CSR_MHPMCOUNTER11 0xb0bU +#define CSR_MHPMCOUNTER12 0xb0cU +#define CSR_MHPMCOUNTER13 0xb0dU +#define CSR_MHPMCOUNTER14 0xb0eU +#define CSR_MHPMCOUNTER15 0xb0fU +#define CSR_MHPMCOUNTER16 0xb10U +#define CSR_MHPMCOUNTER17 0xb11U +#define CSR_MHPMCOUNTER18 0xb12U +#define CSR_MHPMCOUNTER19 0xb13U +#define CSR_MHPMCOUNTER20 0xb14U +#define CSR_MHPMCOUNTER21 0xb15U +#define CSR_MHPMCOUNTER22 0xb16U +#define CSR_MHPMCOUNTER23 0xb17U +#define CSR_MHPMCOUNTER24 0xb18U +#define CSR_MHPMCOUNTER25 0xb19U +#define CSR_MHPMCOUNTER26 0xb1aU +#define CSR_MHPMCOUNTER27 0xb1bU +#define CSR_MHPMCOUNTER28 0xb1cU +#define CSR_MHPMCOUNTER29 0xb1dU +#define CSR_MHPMCOUNTER30 0xb1eU +#define CSR_MHPMCOUNTER31 0xb1fU +#define CSR_MUCOUNTEREN 0x320U +#define CSR_MSCOUNTEREN 0x321U +#define CSR_MHPMEVENT3 0x323U +#define CSR_MHPMEVENT4 0x324U +#define CSR_MHPMEVENT5 0x325U +#define CSR_MHPMEVENT6 0x326U +#define CSR_MHPMEVENT7 0x327U +#define CSR_MHPMEVENT8 0x328U +#define CSR_MHPMEVENT9 0x329U +#define CSR_MHPMEVENT10 0x32aU +#define CSR_MHPMEVENT11 0x32bU +#define CSR_MHPMEVENT12 0x32cU +#define CSR_MHPMEVENT13 0x32dU +#define CSR_MHPMEVENT14 0x32eU +#define CSR_MHPMEVENT15 0x32fU +#define CSR_MHPMEVENT16 0x330U +#define CSR_MHPMEVENT17 0x331U +#define CSR_MHPMEVENT18 0x332U +#define CSR_MHPMEVENT19 0x333U +#define CSR_MHPMEVENT20 0x334U +#define CSR_MHPMEVENT21 0x335U +#define CSR_MHPMEVENT22 0x336U +#define CSR_MHPMEVENT23 0x337U +#define CSR_MHPMEVENT24 0x338U +#define CSR_MHPMEVENT25 0x339U +#define CSR_MHPMEVENT26 0x33aU +#define CSR_MHPMEVENT27 0x33bU +#define CSR_MHPMEVENT28 0x33cU +#define CSR_MHPMEVENT29 0x33dU +#define CSR_MHPMEVENT30 0x33eU +#define CSR_MHPMEVENT31 0x33fU +#define CSR_MVENDORID 0xf11U +#define CSR_MARCHID 0xf12U +#define CSR_MIMPID 0xf13U +#define CSR_MHARTID 0xf14U +#define CSR_CYCLEH 0xc80U +#define CSR_TIMEH 0xc81U +#define CSR_INSTRETH 0xc82U +#define CSR_HPMCOUNTER3H 0xc83U +#define CSR_HPMCOUNTER4H 0xc84U +#define CSR_HPMCOUNTER5H 0xc85U +#define CSR_HPMCOUNTER6H 0xc86U +#define CSR_HPMCOUNTER7H 0xc87U +#define CSR_HPMCOUNTER8H 0xc88U +#define CSR_HPMCOUNTER9H 0xc89U +#define CSR_HPMCOUNTER10H 0xc8aU +#define CSR_HPMCOUNTER11H 0xc8bU +#define CSR_HPMCOUNTER12H 0xc8cU +#define CSR_HPMCOUNTER13H 0xc8dU +#define CSR_HPMCOUNTER14H 0xc8eU +#define CSR_HPMCOUNTER15H 0xc8fU +#define CSR_HPMCOUNTER16H 0xc90U +#define CSR_HPMCOUNTER17H 0xc91U +#define CSR_HPMCOUNTER18H 0xc92U +#define CSR_HPMCOUNTER19H 0xc93U +#define CSR_HPMCOUNTER20H 0xc94U +#define CSR_HPMCOUNTER21H 0xc95U +#define CSR_HPMCOUNTER22H 0xc96U +#define CSR_HPMCOUNTER23H 0xc97U +#define CSR_HPMCOUNTER24H 0xc98U +#define CSR_HPMCOUNTER25H 0xc99U +#define CSR_HPMCOUNTER26H 0xc9aU +#define CSR_HPMCOUNTER27H 0xc9bU +#define CSR_HPMCOUNTER28H 0xc9cU +#define CSR_HPMCOUNTER29H 0xc9dU +#define CSR_HPMCOUNTER30H 0xc9eU +#define CSR_HPMCOUNTER31H 0xc9fU +#define CSR_MCYCLEH 0xb80U +#define CSR_MINSTRETH 0xb82U +#define CSR_MHPMCOUNTER3H 0xb83U +#define CSR_MHPMCOUNTER4H 0xb84U +#define CSR_MHPMCOUNTER5H 0xb85U +#define CSR_MHPMCOUNTER6H 0xb86U +#define CSR_MHPMCOUNTER7H 0xb87U +#define CSR_MHPMCOUNTER8H 0xb88U +#define CSR_MHPMCOUNTER9H 0xb89U +#define CSR_MHPMCOUNTER10H 0xb8aU +#define CSR_MHPMCOUNTER11H 0xb8bU +#define CSR_MHPMCOUNTER12H 0xb8cU +#define CSR_MHPMCOUNTER13H 0xb8dU +#define CSR_MHPMCOUNTER14H 0xb8eU +#define CSR_MHPMCOUNTER15H 0xb8fU +#define CSR_MHPMCOUNTER16H 0xb90U +#define CSR_MHPMCOUNTER17H 0xb91U +#define CSR_MHPMCOUNTER18H 0xb92U +#define CSR_MHPMCOUNTER19H 0xb93U +#define CSR_MHPMCOUNTER20H 0xb94U +#define CSR_MHPMCOUNTER21H 0xb95U +#define CSR_MHPMCOUNTER22H 0xb96U +#define CSR_MHPMCOUNTER23H 0xb97U +#define CSR_MHPMCOUNTER24H 0xb98U +#define CSR_MHPMCOUNTER25H 0xb99U +#define CSR_MHPMCOUNTER26H 0xb9aU +#define CSR_MHPMCOUNTER27H 0xb9bU +#define CSR_MHPMCOUNTER28H 0xb9cU +#define CSR_MHPMCOUNTER29H 0xb9dU +#define CSR_MHPMCOUNTER30H 0xb9eU +#define CSR_MHPMCOUNTER31H 0xb9fU +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FAULT_FETCH 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_FAULT_LOAD 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_FAULT_STORE 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_HYPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#endif +#if defined(DECLARE_INSN) +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(uret, MATCH_URET, MASK_URET) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(hret, MATCH_HRET, MASK_HRET) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) +DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) +DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) +DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) +DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) +DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) +DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) +DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) +DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) +DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) +DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) +DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) +DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) +DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) +DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) +DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) +DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) +DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) +DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) +DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) +DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) +DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) +DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) +DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +#endif +#if defined(DECLARE_CSR) +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sie, CSR_SIE) +DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(sscratch, CSR_SSCRATCH) +DECLARE_CSR(sepc, CSR_SEPC) +DECLARE_CSR(scause, CSR_SCAUSE) +DECLARE_CSR(sbadaddr, CSR_SBADADDR) +DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(sptbr, CSR_SPTBR) +DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(medeleg, CSR_MEDELEG) +DECLARE_CSR(mideleg, CSR_MIDELEG) +DECLARE_CSR(mie, CSR_MIE) +DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mscratch, CSR_MSCRATCH) +DECLARE_CSR(mepc, CSR_MEPC) +DECLARE_CSR(mcause, CSR_MCAUSE) +DECLARE_CSR(mbadaddr, CSR_MBADADDR) +DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(dcsr, CSR_DCSR) +DECLARE_CSR(dpc, CSR_DPC) +DECLARE_CSR(dscratch, CSR_DSCRATCH) +DECLARE_CSR(mcycle, CSR_MCYCLE) +DECLARE_CSR(minstret, CSR_MINSTRET) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN) +DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) +DECLARE_CSR(mvendorid, CSR_MVENDORID) +DECLARE_CSR(marchid, CSR_MARCHID) +DECLARE_CSR(mimpid, CSR_MIMPID) +DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mcycleh, CSR_MCYCLEH) +DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) +#endif +#if defined(DECLARE_CAUSE) +DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) +DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH) +DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) +DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) +DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) +DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD) +DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) +DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE) +DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) +DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +#endif diff --git a/Kboot/src/bootloader_hi/include/fpioa.h b/Kboot/src/bootloader_hi/include/fpioa.h new file mode 100644 index 0000000..c602ae9 --- /dev/null +++ b/Kboot/src/bootloader_hi/include/fpioa.h @@ -0,0 +1,1035 @@ +/* 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 +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Pad number settings */ +#define FPIOA_NUM_IO (48) +/* clang-format on */ + +/** + * @brief FPIOA IO functions + * + * @note FPIOA pin function table + * + * | Function | Name | Description | + * |-----------|------------------|-----------------------------------| + * | 0 | JTAG_TCLK | JTAG Test Clock | + * | 1 | JTAG_TDI | JTAG Test Data In | + * | 2 | JTAG_TMS | JTAG Test Mode Select | + * | 3 | JTAG_TDO | JTAG Test Data Out | + * | 4 | SPI0_D0 | SPI0 Data 0 | + * | 5 | SPI0_D1 | SPI0 Data 1 | + * | 6 | SPI0_D2 | SPI0 Data 2 | + * | 7 | SPI0_D3 | SPI0 Data 3 | + * | 8 | SPI0_D4 | SPI0 Data 4 | + * | 9 | SPI0_D5 | SPI0 Data 5 | + * | 10 | SPI0_D6 | SPI0 Data 6 | + * | 11 | SPI0_D7 | SPI0 Data 7 | + * | 12 | SPI0_SS0 | SPI0 Chip Select 0 | + * | 13 | SPI0_SS1 | SPI0 Chip Select 1 | + * | 14 | SPI0_SS2 | SPI0 Chip Select 2 | + * | 15 | SPI0_SS3 | SPI0 Chip Select 3 | + * | 16 | SPI0_ARB | SPI0 Arbitration | + * | 17 | SPI0_SCLK | SPI0 Serial Clock | + * | 18 | UARTHS_RX | UART High speed Receiver | + * | 19 | UARTHS_TX | UART High speed Transmitter | + * | 20 | RESV6 | Reserved function | + * | 21 | RESV7 | Reserved function | + * | 22 | CLK_SPI1 | Clock SPI1 | + * | 23 | CLK_I2C1 | Clock I2C1 | + * | 24 | GPIOHS0 | GPIO High speed 0 | + * | 25 | GPIOHS1 | GPIO High speed 1 | + * | 26 | GPIOHS2 | GPIO High speed 2 | + * | 27 | GPIOHS3 | GPIO High speed 3 | + * | 28 | GPIOHS4 | GPIO High speed 4 | + * | 29 | GPIOHS5 | GPIO High speed 5 | + * | 30 | GPIOHS6 | GPIO High speed 6 | + * | 31 | GPIOHS7 | GPIO High speed 7 | + * | 32 | GPIOHS8 | GPIO High speed 8 | + * | 33 | GPIOHS9 | GPIO High speed 9 | + * | 34 | GPIOHS10 | GPIO High speed 10 | + * | 35 | GPIOHS11 | GPIO High speed 11 | + * | 36 | GPIOHS12 | GPIO High speed 12 | + * | 37 | GPIOHS13 | GPIO High speed 13 | + * | 38 | GPIOHS14 | GPIO High speed 14 | + * | 39 | GPIOHS15 | GPIO High speed 15 | + * | 40 | GPIOHS16 | GPIO High speed 16 | + * | 41 | GPIOHS17 | GPIO High speed 17 | + * | 42 | GPIOHS18 | GPIO High speed 18 | + * | 43 | GPIOHS19 | GPIO High speed 19 | + * | 44 | GPIOHS20 | GPIO High speed 20 | + * | 45 | GPIOHS21 | GPIO High speed 21 | + * | 46 | GPIOHS22 | GPIO High speed 22 | + * | 47 | GPIOHS23 | GPIO High speed 23 | + * | 48 | GPIOHS24 | GPIO High speed 24 | + * | 49 | GPIOHS25 | GPIO High speed 25 | + * | 50 | GPIOHS26 | GPIO High speed 26 | + * | 51 | GPIOHS27 | GPIO High speed 27 | + * | 52 | GPIOHS28 | GPIO High speed 28 | + * | 53 | GPIOHS29 | GPIO High speed 29 | + * | 54 | GPIOHS30 | GPIO High speed 30 | + * | 55 | GPIOHS31 | GPIO High speed 31 | + * | 56 | GPIO0 | GPIO pin 0 | + * | 57 | GPIO1 | GPIO pin 1 | + * | 58 | GPIO2 | GPIO pin 2 | + * | 59 | GPIO3 | GPIO pin 3 | + * | 60 | GPIO4 | GPIO pin 4 | + * | 61 | GPIO5 | GPIO pin 5 | + * | 62 | GPIO6 | GPIO pin 6 | + * | 63 | GPIO7 | GPIO pin 7 | + * | 64 | UART1_RX | UART1 Receiver | + * | 65 | UART1_TX | UART1 Transmitter | + * | 66 | UART2_RX | UART2 Receiver | + * | 67 | UART2_TX | UART2 Transmitter | + * | 68 | UART3_RX | UART3 Receiver | + * | 69 | UART3_TX | UART3 Transmitter | + * | 70 | SPI1_D0 | SPI1 Data 0 | + * | 71 | SPI1_D1 | SPI1 Data 1 | + * | 72 | SPI1_D2 | SPI1 Data 2 | + * | 73 | SPI1_D3 | SPI1 Data 3 | + * | 74 | SPI1_D4 | SPI1 Data 4 | + * | 75 | SPI1_D5 | SPI1 Data 5 | + * | 76 | SPI1_D6 | SPI1 Data 6 | + * | 77 | SPI1_D7 | SPI1 Data 7 | + * | 78 | SPI1_SS0 | SPI1 Chip Select 0 | + * | 79 | SPI1_SS1 | SPI1 Chip Select 1 | + * | 80 | SPI1_SS2 | SPI1 Chip Select 2 | + * | 81 | SPI1_SS3 | SPI1 Chip Select 3 | + * | 82 | SPI1_ARB | SPI1 Arbitration | + * | 83 | SPI1_SCLK | SPI1 Serial Clock | + * | 84 | SPI_SLAVE_D0 | SPI Slave Data 0 | + * | 85 | SPI_SLAVE_SS | SPI Slave Select | + * | 86 | SPI_SLAVE_SCLK | SPI Slave Serial Clock | + * | 87 | I2S0_MCLK | I2S0 Master Clock | + * | 88 | I2S0_SCLK | I2S0 Serial Clock(BCLK) | + * | 89 | I2S0_WS | I2S0 Word Select(LRCLK) | + * | 90 | I2S0_IN_D0 | I2S0 Serial Data Input 0 | + * | 91 | I2S0_IN_D1 | I2S0 Serial Data Input 1 | + * | 92 | I2S0_IN_D2 | I2S0 Serial Data Input 2 | + * | 93 | I2S0_IN_D3 | I2S0 Serial Data Input 3 | + * | 94 | I2S0_OUT_D0 | I2S0 Serial Data Output 0 | + * | 95 | I2S0_OUT_D1 | I2S0 Serial Data Output 1 | + * | 96 | I2S0_OUT_D2 | I2S0 Serial Data Output 2 | + * | 97 | I2S0_OUT_D3 | I2S0 Serial Data Output 3 | + * | 98 | I2S1_MCLK | I2S1 Master Clock | + * | 99 | I2S1_SCLK | I2S1 Serial Clock(BCLK) | + * | 100 | I2S1_WS | I2S1 Word Select(LRCLK) | + * | 101 | I2S1_IN_D0 | I2S1 Serial Data Input 0 | + * | 102 | I2S1_IN_D1 | I2S1 Serial Data Input 1 | + * | 103 | I2S1_IN_D2 | I2S1 Serial Data Input 2 | + * | 104 | I2S1_IN_D3 | I2S1 Serial Data Input 3 | + * | 105 | I2S1_OUT_D0 | I2S1 Serial Data Output 0 | + * | 106 | I2S1_OUT_D1 | I2S1 Serial Data Output 1 | + * | 107 | I2S1_OUT_D2 | I2S1 Serial Data Output 2 | + * | 108 | I2S1_OUT_D3 | I2S1 Serial Data Output 3 | + * | 109 | I2S2_MCLK | I2S2 Master Clock | + * | 110 | I2S2_SCLK | I2S2 Serial Clock(BCLK) | + * | 111 | I2S2_WS | I2S2 Word Select(LRCLK) | + * | 112 | I2S2_IN_D0 | I2S2 Serial Data Input 0 | + * | 113 | I2S2_IN_D1 | I2S2 Serial Data Input 1 | + * | 114 | I2S2_IN_D2 | I2S2 Serial Data Input 2 | + * | 115 | I2S2_IN_D3 | I2S2 Serial Data Input 3 | + * | 116 | I2S2_OUT_D0 | I2S2 Serial Data Output 0 | + * | 117 | I2S2_OUT_D1 | I2S2 Serial Data Output 1 | + * | 118 | I2S2_OUT_D2 | I2S2 Serial Data Output 2 | + * | 119 | I2S2_OUT_D3 | I2S2 Serial Data Output 3 | + * | 120 | RESV0 | Reserved function | + * | 121 | RESV1 | Reserved function | + * | 122 | RESV2 | Reserved function | + * | 123 | RESV3 | Reserved function | + * | 124 | RESV4 | Reserved function | + * | 125 | RESV5 | Reserved function | + * | 126 | I2C0_SCLK | I2C0 Serial Clock | + * | 127 | I2C0_SDA | I2C0 Serial Data | + * | 128 | I2C1_SCLK | I2C1 Serial Clock | + * | 129 | I2C1_SDA | I2C1 Serial Data | + * | 130 | I2C2_SCLK | I2C2 Serial Clock | + * | 131 | I2C2_SDA | I2C2 Serial Data | + * | 132 | CMOS_XCLK | DVP System Clock | + * | 133 | CMOS_RST | DVP System Reset | + * | 134 | CMOS_PWDN | DVP Power Down Mode | + * | 135 | CMOS_VSYNC | DVP Vertical Sync | + * | 136 | CMOS_HREF | DVP Horizontal Reference output | + * | 137 | CMOS_PCLK | Pixel Clock | + * | 138 | CMOS_D0 | Data Bit 0 | + * | 139 | CMOS_D1 | Data Bit 1 | + * | 140 | CMOS_D2 | Data Bit 2 | + * | 141 | CMOS_D3 | Data Bit 3 | + * | 142 | CMOS_D4 | Data Bit 4 | + * | 143 | CMOS_D5 | Data Bit 5 | + * | 144 | CMOS_D6 | Data Bit 6 | + * | 145 | CMOS_D7 | Data Bit 7 | + * | 146 | SCCB_SCLK | SCCB Serial Clock | + * | 147 | SCCB_SDA | SCCB Serial Data | + * | 148 | UART1_CTS | UART1 Clear To Send | + * | 149 | UART1_DSR | UART1 Data Set Ready | + * | 150 | UART1_DCD | UART1 Data Carrier Detect | + * | 151 | UART1_RI | UART1 Ring Indicator | + * | 152 | UART1_SIR_IN | UART1 Serial Infrared Input | + * | 153 | UART1_DTR | UART1 Data Terminal Ready | + * | 154 | UART1_RTS | UART1 Request To Send | + * | 155 | UART1_OUT2 | UART1 User-designated Output 2 | + * | 156 | UART1_OUT1 | UART1 User-designated Output 1 | + * | 157 | UART1_SIR_OUT | UART1 Serial Infrared Output | + * | 158 | UART1_BAUD | UART1 Transmit Clock Output | + * | 159 | UART1_RE | UART1 Receiver Output Enable | + * | 160 | UART1_DE | UART1 Driver Output Enable | + * | 161 | UART1_RS485_EN | UART1 RS485 Enable | + * | 162 | UART2_CTS | UART2 Clear To Send | + * | 163 | UART2_DSR | UART2 Data Set Ready | + * | 164 | UART2_DCD | UART2 Data Carrier Detect | + * | 165 | UART2_RI | UART2 Ring Indicator | + * | 166 | UART2_SIR_IN | UART2 Serial Infrared Input | + * | 167 | UART2_DTR | UART2 Data Terminal Ready | + * | 168 | UART2_RTS | UART2 Request To Send | + * | 169 | UART2_OUT2 | UART2 User-designated Output 2 | + * | 170 | UART2_OUT1 | UART2 User-designated Output 1 | + * | 171 | UART2_SIR_OUT | UART2 Serial Infrared Output | + * | 172 | UART2_BAUD | UART2 Transmit Clock Output | + * | 173 | UART2_RE | UART2 Receiver Output Enable | + * | 174 | UART2_DE | UART2 Driver Output Enable | + * | 175 | UART2_RS485_EN | UART2 RS485 Enable | + * | 176 | UART3_CTS | UART3 Clear To Send | + * | 177 | UART3_DSR | UART3 Data Set Ready | + * | 178 | UART3_DCD | UART3 Data Carrier Detect | + * | 179 | UART3_RI | UART3 Ring Indicator | + * | 180 | UART3_SIR_IN | UART3 Serial Infrared Input | + * | 181 | UART3_DTR | UART3 Data Terminal Ready | + * | 182 | UART3_RTS | UART3 Request To Send | + * | 183 | UART3_OUT2 | UART3 User-designated Output 2 | + * | 184 | UART3_OUT1 | UART3 User-designated Output 1 | + * | 185 | UART3_SIR_OUT | UART3 Serial Infrared Output | + * | 186 | UART3_BAUD | UART3 Transmit Clock Output | + * | 187 | UART3_RE | UART3 Receiver Output Enable | + * | 188 | UART3_DE | UART3 Driver Output Enable | + * | 189 | UART3_RS485_EN | UART3 RS485 Enable | + * | 190 | TIMER0_TOGGLE1 | TIMER0 Toggle Output 1 | + * | 191 | TIMER0_TOGGLE2 | TIMER0 Toggle Output 2 | + * | 192 | TIMER0_TOGGLE3 | TIMER0 Toggle Output 3 | + * | 193 | TIMER0_TOGGLE4 | TIMER0 Toggle Output 4 | + * | 194 | TIMER1_TOGGLE1 | TIMER1 Toggle Output 1 | + * | 195 | TIMER1_TOGGLE2 | TIMER1 Toggle Output 2 | + * | 196 | TIMER1_TOGGLE3 | TIMER1 Toggle Output 3 | + * | 197 | TIMER1_TOGGLE4 | TIMER1 Toggle Output 4 | + * | 198 | TIMER2_TOGGLE1 | TIMER2 Toggle Output 1 | + * | 199 | TIMER2_TOGGLE2 | TIMER2 Toggle Output 2 | + * | 200 | TIMER2_TOGGLE3 | TIMER2 Toggle Output 3 | + * | 201 | TIMER2_TOGGLE4 | TIMER2 Toggle Output 4 | + * | 202 | CLK_SPI2 | Clock SPI2 | + * | 203 | CLK_I2C2 | Clock I2C2 | + * | 204 | INTERNAL0 | Internal function signal 0 | + * | 205 | INTERNAL1 | Internal function signal 1 | + * | 206 | INTERNAL2 | Internal function signal 2 | + * | 207 | INTERNAL3 | Internal function signal 3 | + * | 208 | INTERNAL4 | Internal function signal 4 | + * | 209 | INTERNAL5 | Internal function signal 5 | + * | 210 | INTERNAL6 | Internal function signal 6 | + * | 211 | INTERNAL7 | Internal function signal 7 | + * | 212 | INTERNAL8 | Internal function signal 8 | + * | 213 | INTERNAL9 | Internal function signal 9 | + * | 214 | INTERNAL10 | Internal function signal 10 | + * | 215 | INTERNAL11 | Internal function signal 11 | + * | 216 | INTERNAL12 | Internal function signal 12 | + * | 217 | INTERNAL13 | Internal function signal 13 | + * | 218 | INTERNAL14 | Internal function signal 14 | + * | 219 | INTERNAL15 | Internal function signal 15 | + * | 220 | INTERNAL16 | Internal function signal 16 | + * | 221 | INTERNAL17 | Internal function signal 17 | + * | 222 | CONSTANT | Constant function | + * | 223 | INTERNAL18 | Internal function signal 18 | + * | 224 | DEBUG0 | Debug function 0 | + * | 225 | DEBUG1 | Debug function 1 | + * | 226 | DEBUG2 | Debug function 2 | + * | 227 | DEBUG3 | Debug function 3 | + * | 228 | DEBUG4 | Debug function 4 | + * | 229 | DEBUG5 | Debug function 5 | + * | 230 | DEBUG6 | Debug function 6 | + * | 231 | DEBUG7 | Debug function 7 | + * | 232 | DEBUG8 | Debug function 8 | + * | 233 | DEBUG9 | Debug function 9 | + * | 234 | DEBUG10 | Debug function 10 | + * | 235 | DEBUG11 | Debug function 11 | + * | 236 | DEBUG12 | Debug function 12 | + * | 237 | DEBUG13 | Debug function 13 | + * | 238 | DEBUG14 | Debug function 14 | + * | 239 | DEBUG15 | Debug function 15 | + * | 240 | DEBUG16 | Debug function 16 | + * | 241 | DEBUG17 | Debug function 17 | + * | 242 | DEBUG18 | Debug function 18 | + * | 243 | DEBUG19 | Debug function 19 | + * | 244 | DEBUG20 | Debug function 20 | + * | 245 | DEBUG21 | Debug function 21 | + * | 246 | DEBUG22 | Debug function 22 | + * | 247 | DEBUG23 | Debug function 23 | + * | 248 | DEBUG24 | Debug function 24 | + * | 249 | DEBUG25 | Debug function 25 | + * | 250 | DEBUG26 | Debug function 26 | + * | 251 | DEBUG27 | Debug function 27 | + * | 252 | DEBUG28 | Debug function 28 | + * | 253 | DEBUG29 | Debug function 29 | + * | 254 | DEBUG30 | Debug function 30 | + * | 255 | DEBUG31 | Debug function 31 | + * + * Any IO of FPIOA have 256 functions, it is a IO-function matrix. + * All IO have default reset function, after reset, re-configure + * IO function is required. + */ + +/* clang-format off */ +typedef enum _fpioa_function +{ + FUNC_JTAG_TCLK = 0, /*!< JTAG Test Clock */ + FUNC_JTAG_TDI = 1, /*!< JTAG Test Data In */ + FUNC_JTAG_TMS = 2, /*!< JTAG Test Mode Select */ + FUNC_JTAG_TDO = 3, /*!< JTAG Test Data Out */ + FUNC_SPI0_D0 = 4, /*!< SPI0 Data 0 */ + FUNC_SPI0_D1 = 5, /*!< SPI0 Data 1 */ + FUNC_SPI0_D2 = 6, /*!< SPI0 Data 2 */ + FUNC_SPI0_D3 = 7, /*!< SPI0 Data 3 */ + FUNC_SPI0_D4 = 8, /*!< SPI0 Data 4 */ + FUNC_SPI0_D5 = 9, /*!< SPI0 Data 5 */ + FUNC_SPI0_D6 = 10, /*!< SPI0 Data 6 */ + FUNC_SPI0_D7 = 11, /*!< SPI0 Data 7 */ + FUNC_SPI0_SS0 = 12, /*!< SPI0 Chip Select 0 */ + FUNC_SPI0_SS1 = 13, /*!< SPI0 Chip Select 1 */ + FUNC_SPI0_SS2 = 14, /*!< SPI0 Chip Select 2 */ + FUNC_SPI0_SS3 = 15, /*!< SPI0 Chip Select 3 */ + FUNC_SPI0_ARB = 16, /*!< SPI0 Arbitration */ + FUNC_SPI0_SCLK = 17, /*!< SPI0 Serial Clock */ + FUNC_UARTHS_RX = 18, /*!< UART High speed Receiver */ + FUNC_UARTHS_TX = 19, /*!< UART High speed Transmitter */ + FUNC_RESV6 = 20, /*!< Reserved function */ + FUNC_RESV7 = 21, /*!< Reserved function */ + FUNC_CLK_SPI1 = 22, /*!< Clock SPI1 */ + FUNC_CLK_I2C1 = 23, /*!< Clock I2C1 */ + FUNC_GPIOHS0 = 24, /*!< GPIO High speed 0 */ + FUNC_GPIOHS1 = 25, /*!< GPIO High speed 1 */ + FUNC_GPIOHS2 = 26, /*!< GPIO High speed 2 */ + FUNC_GPIOHS3 = 27, /*!< GPIO High speed 3 */ + FUNC_GPIOHS4 = 28, /*!< GPIO High speed 4 */ + FUNC_GPIOHS5 = 29, /*!< GPIO High speed 5 */ + FUNC_GPIOHS6 = 30, /*!< GPIO High speed 6 */ + FUNC_GPIOHS7 = 31, /*!< GPIO High speed 7 */ + FUNC_GPIOHS8 = 32, /*!< GPIO High speed 8 */ + FUNC_GPIOHS9 = 33, /*!< GPIO High speed 9 */ + FUNC_GPIOHS10 = 34, /*!< GPIO High speed 10 */ + FUNC_GPIOHS11 = 35, /*!< GPIO High speed 11 */ + FUNC_GPIOHS12 = 36, /*!< GPIO High speed 12 */ + FUNC_GPIOHS13 = 37, /*!< GPIO High speed 13 */ + FUNC_GPIOHS14 = 38, /*!< GPIO High speed 14 */ + FUNC_GPIOHS15 = 39, /*!< GPIO High speed 15 */ + FUNC_GPIOHS16 = 40, /*!< GPIO High speed 16 */ + FUNC_GPIOHS17 = 41, /*!< GPIO High speed 17 */ + FUNC_GPIOHS18 = 42, /*!< GPIO High speed 18 */ + FUNC_GPIOHS19 = 43, /*!< GPIO High speed 19 */ + FUNC_GPIOHS20 = 44, /*!< GPIO High speed 20 */ + FUNC_GPIOHS21 = 45, /*!< GPIO High speed 21 */ + FUNC_GPIOHS22 = 46, /*!< GPIO High speed 22 */ + FUNC_GPIOHS23 = 47, /*!< GPIO High speed 23 */ + FUNC_GPIOHS24 = 48, /*!< GPIO High speed 24 */ + FUNC_GPIOHS25 = 49, /*!< GPIO High speed 25 */ + FUNC_GPIOHS26 = 50, /*!< GPIO High speed 26 */ + FUNC_GPIOHS27 = 51, /*!< GPIO High speed 27 */ + FUNC_GPIOHS28 = 52, /*!< GPIO High speed 28 */ + FUNC_GPIOHS29 = 53, /*!< GPIO High speed 29 */ + FUNC_GPIOHS30 = 54, /*!< GPIO High speed 30 */ + FUNC_GPIOHS31 = 55, /*!< GPIO High speed 31 */ + FUNC_GPIO0 = 56, /*!< GPIO pin 0 */ + FUNC_GPIO1 = 57, /*!< GPIO pin 1 */ + FUNC_GPIO2 = 58, /*!< GPIO pin 2 */ + FUNC_GPIO3 = 59, /*!< GPIO pin 3 */ + FUNC_GPIO4 = 60, /*!< GPIO pin 4 */ + FUNC_GPIO5 = 61, /*!< GPIO pin 5 */ + FUNC_GPIO6 = 62, /*!< GPIO pin 6 */ + FUNC_GPIO7 = 63, /*!< GPIO pin 7 */ + FUNC_UART1_RX = 64, /*!< UART1 Receiver */ + FUNC_UART1_TX = 65, /*!< UART1 Transmitter */ + FUNC_UART2_RX = 66, /*!< UART2 Receiver */ + FUNC_UART2_TX = 67, /*!< UART2 Transmitter */ + FUNC_UART3_RX = 68, /*!< UART3 Receiver */ + FUNC_UART3_TX = 69, /*!< UART3 Transmitter */ + FUNC_SPI1_D0 = 70, /*!< SPI1 Data 0 */ + FUNC_SPI1_D1 = 71, /*!< SPI1 Data 1 */ + FUNC_SPI1_D2 = 72, /*!< SPI1 Data 2 */ + FUNC_SPI1_D3 = 73, /*!< SPI1 Data 3 */ + FUNC_SPI1_D4 = 74, /*!< SPI1 Data 4 */ + FUNC_SPI1_D5 = 75, /*!< SPI1 Data 5 */ + FUNC_SPI1_D6 = 76, /*!< SPI1 Data 6 */ + FUNC_SPI1_D7 = 77, /*!< SPI1 Data 7 */ + FUNC_SPI1_SS0 = 78, /*!< SPI1 Chip Select 0 */ + FUNC_SPI1_SS1 = 79, /*!< SPI1 Chip Select 1 */ + FUNC_SPI1_SS2 = 80, /*!< SPI1 Chip Select 2 */ + FUNC_SPI1_SS3 = 81, /*!< SPI1 Chip Select 3 */ + FUNC_SPI1_ARB = 82, /*!< SPI1 Arbitration */ + FUNC_SPI1_SCLK = 83, /*!< SPI1 Serial Clock */ + FUNC_SPI_SLAVE_D0 = 84, /*!< SPI Slave Data 0 */ + FUNC_SPI_SLAVE_SS = 85, /*!< SPI Slave Select */ + FUNC_SPI_SLAVE_SCLK = 86, /*!< SPI Slave Serial Clock */ + FUNC_I2S0_MCLK = 87, /*!< I2S0 Master Clock */ + FUNC_I2S0_SCLK = 88, /*!< I2S0 Serial Clock(BCLK) */ + FUNC_I2S0_WS = 89, /*!< I2S0 Word Select(LRCLK) */ + FUNC_I2S0_IN_D0 = 90, /*!< I2S0 Serial Data Input 0 */ + FUNC_I2S0_IN_D1 = 91, /*!< I2S0 Serial Data Input 1 */ + FUNC_I2S0_IN_D2 = 92, /*!< I2S0 Serial Data Input 2 */ + FUNC_I2S0_IN_D3 = 93, /*!< I2S0 Serial Data Input 3 */ + FUNC_I2S0_OUT_D0 = 94, /*!< I2S0 Serial Data Output 0 */ + FUNC_I2S0_OUT_D1 = 95, /*!< I2S0 Serial Data Output 1 */ + FUNC_I2S0_OUT_D2 = 96, /*!< I2S0 Serial Data Output 2 */ + FUNC_I2S0_OUT_D3 = 97, /*!< I2S0 Serial Data Output 3 */ + FUNC_I2S1_MCLK = 98, /*!< I2S1 Master Clock */ + FUNC_I2S1_SCLK = 99, /*!< I2S1 Serial Clock(BCLK) */ + FUNC_I2S1_WS = 100, /*!< I2S1 Word Select(LRCLK) */ + FUNC_I2S1_IN_D0 = 101, /*!< I2S1 Serial Data Input 0 */ + FUNC_I2S1_IN_D1 = 102, /*!< I2S1 Serial Data Input 1 */ + FUNC_I2S1_IN_D2 = 103, /*!< I2S1 Serial Data Input 2 */ + FUNC_I2S1_IN_D3 = 104, /*!< I2S1 Serial Data Input 3 */ + FUNC_I2S1_OUT_D0 = 105, /*!< I2S1 Serial Data Output 0 */ + FUNC_I2S1_OUT_D1 = 106, /*!< I2S1 Serial Data Output 1 */ + FUNC_I2S1_OUT_D2 = 107, /*!< I2S1 Serial Data Output 2 */ + FUNC_I2S1_OUT_D3 = 108, /*!< I2S1 Serial Data Output 3 */ + FUNC_I2S2_MCLK = 109, /*!< I2S2 Master Clock */ + FUNC_I2S2_SCLK = 110, /*!< I2S2 Serial Clock(BCLK) */ + FUNC_I2S2_WS = 111, /*!< I2S2 Word Select(LRCLK) */ + FUNC_I2S2_IN_D0 = 112, /*!< I2S2 Serial Data Input 0 */ + FUNC_I2S2_IN_D1 = 113, /*!< I2S2 Serial Data Input 1 */ + FUNC_I2S2_IN_D2 = 114, /*!< I2S2 Serial Data Input 2 */ + FUNC_I2S2_IN_D3 = 115, /*!< I2S2 Serial Data Input 3 */ + FUNC_I2S2_OUT_D0 = 116, /*!< I2S2 Serial Data Output 0 */ + FUNC_I2S2_OUT_D1 = 117, /*!< I2S2 Serial Data Output 1 */ + FUNC_I2S2_OUT_D2 = 118, /*!< I2S2 Serial Data Output 2 */ + FUNC_I2S2_OUT_D3 = 119, /*!< I2S2 Serial Data Output 3 */ + FUNC_RESV0 = 120, /*!< Reserved function */ + FUNC_RESV1 = 121, /*!< Reserved function */ + FUNC_RESV2 = 122, /*!< Reserved function */ + FUNC_RESV3 = 123, /*!< Reserved function */ + FUNC_RESV4 = 124, /*!< Reserved function */ + FUNC_RESV5 = 125, /*!< Reserved function */ + FUNC_I2C0_SCLK = 126, /*!< I2C0 Serial Clock */ + FUNC_I2C0_SDA = 127, /*!< I2C0 Serial Data */ + FUNC_I2C1_SCLK = 128, /*!< I2C1 Serial Clock */ + FUNC_I2C1_SDA = 129, /*!< I2C1 Serial Data */ + FUNC_I2C2_SCLK = 130, /*!< I2C2 Serial Clock */ + FUNC_I2C2_SDA = 131, /*!< I2C2 Serial Data */ + FUNC_CMOS_XCLK = 132, /*!< DVP System Clock */ + FUNC_CMOS_RST = 133, /*!< DVP System Reset */ + FUNC_CMOS_PWDN = 134, /*!< DVP Power Down Mode */ + FUNC_CMOS_VSYNC = 135, /*!< DVP Vertical Sync */ + FUNC_CMOS_HREF = 136, /*!< DVP Horizontal Reference output */ + FUNC_CMOS_PCLK = 137, /*!< Pixel Clock */ + FUNC_CMOS_D0 = 138, /*!< Data Bit 0 */ + FUNC_CMOS_D1 = 139, /*!< Data Bit 1 */ + FUNC_CMOS_D2 = 140, /*!< Data Bit 2 */ + FUNC_CMOS_D3 = 141, /*!< Data Bit 3 */ + FUNC_CMOS_D4 = 142, /*!< Data Bit 4 */ + FUNC_CMOS_D5 = 143, /*!< Data Bit 5 */ + FUNC_CMOS_D6 = 144, /*!< Data Bit 6 */ + FUNC_CMOS_D7 = 145, /*!< Data Bit 7 */ + FUNC_SCCB_SCLK = 146, /*!< SCCB Serial Clock */ + FUNC_SCCB_SDA = 147, /*!< SCCB Serial Data */ + FUNC_UART1_CTS = 148, /*!< UART1 Clear To Send */ + FUNC_UART1_DSR = 149, /*!< UART1 Data Set Ready */ + FUNC_UART1_DCD = 150, /*!< UART1 Data Carrier Detect */ + FUNC_UART1_RI = 151, /*!< UART1 Ring Indicator */ + FUNC_UART1_SIR_IN = 152, /*!< UART1 Serial Infrared Input */ + FUNC_UART1_DTR = 153, /*!< UART1 Data Terminal Ready */ + FUNC_UART1_RTS = 154, /*!< UART1 Request To Send */ + FUNC_UART1_OUT2 = 155, /*!< UART1 User-designated Output 2 */ + FUNC_UART1_OUT1 = 156, /*!< UART1 User-designated Output 1 */ + FUNC_UART1_SIR_OUT = 157, /*!< UART1 Serial Infrared Output */ + FUNC_UART1_BAUD = 158, /*!< UART1 Transmit Clock Output */ + FUNC_UART1_RE = 159, /*!< UART1 Receiver Output Enable */ + FUNC_UART1_DE = 160, /*!< UART1 Driver Output Enable */ + FUNC_UART1_RS485_EN = 161, /*!< UART1 RS485 Enable */ + FUNC_UART2_CTS = 162, /*!< UART2 Clear To Send */ + FUNC_UART2_DSR = 163, /*!< UART2 Data Set Ready */ + FUNC_UART2_DCD = 164, /*!< UART2 Data Carrier Detect */ + FUNC_UART2_RI = 165, /*!< UART2 Ring Indicator */ + FUNC_UART2_SIR_IN = 166, /*!< UART2 Serial Infrared Input */ + FUNC_UART2_DTR = 167, /*!< UART2 Data Terminal Ready */ + FUNC_UART2_RTS = 168, /*!< UART2 Request To Send */ + FUNC_UART2_OUT2 = 169, /*!< UART2 User-designated Output 2 */ + FUNC_UART2_OUT1 = 170, /*!< UART2 User-designated Output 1 */ + FUNC_UART2_SIR_OUT = 171, /*!< UART2 Serial Infrared Output */ + FUNC_UART2_BAUD = 172, /*!< UART2 Transmit Clock Output */ + FUNC_UART2_RE = 173, /*!< UART2 Receiver Output Enable */ + FUNC_UART2_DE = 174, /*!< UART2 Driver Output Enable */ + FUNC_UART2_RS485_EN = 175, /*!< UART2 RS485 Enable */ + FUNC_UART3_CTS = 176, /*!< UART3 Clear To Send */ + FUNC_UART3_DSR = 177, /*!< UART3 Data Set Ready */ + FUNC_UART3_DCD = 178, /*!< UART3 Data Carrier Detect */ + FUNC_UART3_RI = 179, /*!< UART3 Ring Indicator */ + FUNC_UART3_SIR_IN = 180, /*!< UART3 Serial Infrared Input */ + FUNC_UART3_DTR = 181, /*!< UART3 Data Terminal Ready */ + FUNC_UART3_RTS = 182, /*!< UART3 Request To Send */ + FUNC_UART3_OUT2 = 183, /*!< UART3 User-designated Output 2 */ + FUNC_UART3_OUT1 = 184, /*!< UART3 User-designated Output 1 */ + FUNC_UART3_SIR_OUT = 185, /*!< UART3 Serial Infrared Output */ + FUNC_UART3_BAUD = 186, /*!< UART3 Transmit Clock Output */ + FUNC_UART3_RE = 187, /*!< UART3 Receiver Output Enable */ + FUNC_UART3_DE = 188, /*!< UART3 Driver Output Enable */ + FUNC_UART3_RS485_EN = 189, /*!< UART3 RS485 Enable */ + FUNC_TIMER0_TOGGLE1 = 190, /*!< TIMER0 Toggle Output 1 */ + FUNC_TIMER0_TOGGLE2 = 191, /*!< TIMER0 Toggle Output 2 */ + FUNC_TIMER0_TOGGLE3 = 192, /*!< TIMER0 Toggle Output 3 */ + FUNC_TIMER0_TOGGLE4 = 193, /*!< TIMER0 Toggle Output 4 */ + FUNC_TIMER1_TOGGLE1 = 194, /*!< TIMER1 Toggle Output 1 */ + FUNC_TIMER1_TOGGLE2 = 195, /*!< TIMER1 Toggle Output 2 */ + FUNC_TIMER1_TOGGLE3 = 196, /*!< TIMER1 Toggle Output 3 */ + FUNC_TIMER1_TOGGLE4 = 197, /*!< TIMER1 Toggle Output 4 */ + FUNC_TIMER2_TOGGLE1 = 198, /*!< TIMER2 Toggle Output 1 */ + FUNC_TIMER2_TOGGLE2 = 199, /*!< TIMER2 Toggle Output 2 */ + FUNC_TIMER2_TOGGLE3 = 200, /*!< TIMER2 Toggle Output 3 */ + FUNC_TIMER2_TOGGLE4 = 201, /*!< TIMER2 Toggle Output 4 */ + FUNC_CLK_SPI2 = 202, /*!< Clock SPI2 */ + FUNC_CLK_I2C2 = 203, /*!< Clock I2C2 */ + FUNC_INTERNAL0 = 204, /*!< Internal function signal 0 */ + FUNC_INTERNAL1 = 205, /*!< Internal function signal 1 */ + FUNC_INTERNAL2 = 206, /*!< Internal function signal 2 */ + FUNC_INTERNAL3 = 207, /*!< Internal function signal 3 */ + FUNC_INTERNAL4 = 208, /*!< Internal function signal 4 */ + FUNC_INTERNAL5 = 209, /*!< Internal function signal 5 */ + FUNC_INTERNAL6 = 210, /*!< Internal function signal 6 */ + FUNC_INTERNAL7 = 211, /*!< Internal function signal 7 */ + FUNC_INTERNAL8 = 212, /*!< Internal function signal 8 */ + FUNC_INTERNAL9 = 213, /*!< Internal function signal 9 */ + FUNC_INTERNAL10 = 214, /*!< Internal function signal 10 */ + FUNC_INTERNAL11 = 215, /*!< Internal function signal 11 */ + FUNC_INTERNAL12 = 216, /*!< Internal function signal 12 */ + FUNC_INTERNAL13 = 217, /*!< Internal function signal 13 */ + FUNC_INTERNAL14 = 218, /*!< Internal function signal 14 */ + FUNC_INTERNAL15 = 219, /*!< Internal function signal 15 */ + FUNC_INTERNAL16 = 220, /*!< Internal function signal 16 */ + FUNC_INTERNAL17 = 221, /*!< Internal function signal 17 */ + FUNC_CONSTANT = 222, /*!< Constant function */ + FUNC_INTERNAL18 = 223, /*!< Internal function signal 18 */ + FUNC_DEBUG0 = 224, /*!< Debug function 0 */ + FUNC_DEBUG1 = 225, /*!< Debug function 1 */ + FUNC_DEBUG2 = 226, /*!< Debug function 2 */ + FUNC_DEBUG3 = 227, /*!< Debug function 3 */ + FUNC_DEBUG4 = 228, /*!< Debug function 4 */ + FUNC_DEBUG5 = 229, /*!< Debug function 5 */ + FUNC_DEBUG6 = 230, /*!< Debug function 6 */ + FUNC_DEBUG7 = 231, /*!< Debug function 7 */ + FUNC_DEBUG8 = 232, /*!< Debug function 8 */ + FUNC_DEBUG9 = 233, /*!< Debug function 9 */ + FUNC_DEBUG10 = 234, /*!< Debug function 10 */ + FUNC_DEBUG11 = 235, /*!< Debug function 11 */ + FUNC_DEBUG12 = 236, /*!< Debug function 12 */ + FUNC_DEBUG13 = 237, /*!< Debug function 13 */ + FUNC_DEBUG14 = 238, /*!< Debug function 14 */ + FUNC_DEBUG15 = 239, /*!< Debug function 15 */ + FUNC_DEBUG16 = 240, /*!< Debug function 16 */ + FUNC_DEBUG17 = 241, /*!< Debug function 17 */ + FUNC_DEBUG18 = 242, /*!< Debug function 18 */ + FUNC_DEBUG19 = 243, /*!< Debug function 19 */ + FUNC_DEBUG20 = 244, /*!< Debug function 20 */ + FUNC_DEBUG21 = 245, /*!< Debug function 21 */ + FUNC_DEBUG22 = 246, /*!< Debug function 22 */ + FUNC_DEBUG23 = 247, /*!< Debug function 23 */ + FUNC_DEBUG24 = 248, /*!< Debug function 24 */ + FUNC_DEBUG25 = 249, /*!< Debug function 25 */ + FUNC_DEBUG26 = 250, /*!< Debug function 26 */ + FUNC_DEBUG27 = 251, /*!< Debug function 27 */ + FUNC_DEBUG28 = 252, /*!< Debug function 28 */ + FUNC_DEBUG29 = 253, /*!< Debug function 29 */ + FUNC_DEBUG30 = 254, /*!< Debug function 30 */ + FUNC_DEBUG31 = 255, /*!< Debug function 31 */ + FUNC_MAX = 256, /*!< Function numbers */ +} fpioa_function_t; +/* clang-format on */ + +/** + * @brief FPIOA pull settings + * + * @note FPIOA pull settings description + * + * | PU | PD | Description | + * |-----|-----|-----------------------------------| + * | 0 | 0 | No Pull | + * | 0 | 1 | Pull Down | + * | 1 | 0 | Pull Up | + * | 1 | 1 | Undefined | + * + */ + +/* clang-format off */ +typedef enum _fpioa_pull +{ + FPIOA_PULL_NONE, /*!< No Pull */ + FPIOA_PULL_DOWN, /*!< Pull Down */ + FPIOA_PULL_UP, /*!< Pull Up */ + FPIOA_PULL_MAX /*!< Count of pull settings */ +} fpioa_pull_t; +/* clang-format on */ + +/** + * @brief FPIOA driving settings + * + * @note FPIOA driving settings description + * There are 16 kinds of driving settings + * + * @note Low Level Output Current + * + * |DS[3:0] |Min(mA)|Typ(mA)|Max(mA)| + * |--------|-------|-------|-------| + * |0000 |3.2 |5.4 |8.3 | + * |0001 |4.7 |8.0 |12.3 | + * |0010 |6.3 |10.7 |16.4 | + * |0011 |7.8 |13.2 |20.2 | + * |0100 |9.4 |15.9 |24.2 | + * |0101 |10.9 |18.4 |28.1 | + * |0110 |12.4 |20.9 |31.8 | + * |0111 |13.9 |23.4 |35.5 | + * + * @note High Level Output Current + * + * |DS[3:0] |Min(mA)|Typ(mA)|Max(mA)| + * |--------|-------|-------|-------| + * |0000 |5.0 |7.6 |11.2 | + * |0001 |7.5 |11.4 |16.8 | + * |0010 |10.0 |15.2 |22.3 | + * |0011 |12.4 |18.9 |27.8 | + * |0100 |14.9 |22.6 |33.3 | + * |0101 |17.4 |26.3 |38.7 | + * |0110 |19.8 |30.0 |44.1 | + * |0111 |22.3 |33.7 |49.5 | + * + */ + +/* clang-format off */ +typedef enum _fpioa_driving +{ + FPIOA_DRIVING_0, /*!< 0000 */ + FPIOA_DRIVING_1, /*!< 0001 */ + FPIOA_DRIVING_2, /*!< 0010 */ + FPIOA_DRIVING_3, /*!< 0011 */ + FPIOA_DRIVING_4, /*!< 0100 */ + FPIOA_DRIVING_5, /*!< 0101 */ + FPIOA_DRIVING_6, /*!< 0110 */ + FPIOA_DRIVING_7, /*!< 0111 */ + FPIOA_DRIVING_8, /*!< 1000 */ + FPIOA_DRIVING_9, /*!< 1001 */ + FPIOA_DRIVING_10, /*!< 1010 */ + FPIOA_DRIVING_11, /*!< 1011 */ + FPIOA_DRIVING_12, /*!< 1100 */ + FPIOA_DRIVING_13, /*!< 1101 */ + FPIOA_DRIVING_14, /*!< 1110 */ + FPIOA_DRIVING_15, /*!< 1111 */ + FPIOA_DRIVING_MAX /*!< Count of driving settings */ +} fpioa_driving_t; +/* clang-format on */ + +/** + * @brief FPIOA IO + * + * FPIOA IO is the specific pin of the chip package. Every IO + * has a 32bit width register that can independently implement + * schmitt trigger, invert input, invert output, strong pull + * up, driving selector, static input and static output. And more, + * it can implement any pin of any peripheral devices. + * + * @note FPIOA IO's register bits Layout + * + * | Bits | Name |Description | + * |-----------|----------|---------------------------------------------------| + * | 31 | PAD_DI | Read current IO's data input. | + * | 30:24 | NA | Reserved bits. | + * | 23 | ST | Schmitt trigger. | + * | 22 | DI_INV | Invert Data input. | + * | 21 | IE_INV | Invert the input enable signal. | + * | 20 | IE_EN | Input enable. It can disable or enable IO input. | + * | 19 | SL | Slew rate control enable. | + * | 18 | SPU | Strong pull up. | + * | 17 | PD | Pull select: 0 for pull down, 1 for pull up. | + * | 16 | PU | Pull enable. | + * | 15 | DO_INV | Invert the result of data output select (DO_SEL). | + * | 14 | DO_SEL | Data output select: 0 for DO, 1 for OE. | + * | 13 | OE_INV | Invert the output enable signal. | + * | 12 | OE_EN | Output enable.It can disable or enable IO output. | + * | 11:8 | DS | Driving selector. | + * | 7:0 | CH_SEL | Channel select from 256 input. | + * + */ +typedef struct _fpioa_io_config +{ + uint32_t ch_sel : 8; + /*!< Channel select from 256 input. */ + uint32_t ds : 4; + /*!< Driving selector. */ + uint32_t oe_en : 1; + /*!< Static output enable, will AND with OE_INV. */ + uint32_t oe_inv : 1; + /*!< Invert output enable. */ + uint32_t do_sel : 1; + /*!< Data output select: 0 for DO, 1 for OE. */ + uint32_t do_inv : 1; + /*!< Invert the result of data output select (DO_SEL). */ + uint32_t pu : 1; + /*!< Pull up enable. 0 for nothing, 1 for pull up. */ + uint32_t pd : 1; + /*!< Pull down enable. 0 for nothing, 1 for pull down. */ + uint32_t resv0 : 1; + /*!< Reserved bits. */ + uint32_t sl : 1; + /*!< Slew rate control enable. */ + uint32_t ie_en : 1; + /*!< Static input enable, will AND with IE_INV. */ + uint32_t ie_inv : 1; + /*!< Invert input enable. */ + uint32_t di_inv : 1; + /*!< Invert Data input. */ + uint32_t st : 1; + /*!< Schmitt trigger. */ + uint32_t resv1 : 7; + /*!< Reserved bits. */ + uint32_t pad_di : 1; + /*!< Read current IO's data input. */ +} __attribute__((packed, aligned(4))) fpioa_io_config_t; + +/** + * @brief FPIOA tie setting + * + * FPIOA Object have 48 IO pin object and 256 bit input tie bits. + * All SPI arbitration signal will tie high by default. + * + * @note FPIOA function tie bits RAM Layout + * + * | Address | Name |Description | + * |-----------|------------------|----------------------------------| + * | 0x000 | TIE_EN[31:0] | Input tie enable bits [31:0] | + * | 0x004 | TIE_EN[63:32] | Input tie enable bits [63:32] | + * | 0x008 | TIE_EN[95:64] | Input tie enable bits [95:64] | + * | 0x00C | TIE_EN[127:96] | Input tie enable bits [127:96] | + * | 0x010 | TIE_EN[159:128] | Input tie enable bits [159:128] | + * | 0x014 | TIE_EN[191:160] | Input tie enable bits [191:160] | + * | 0x018 | TIE_EN[223:192] | Input tie enable bits [223:192] | + * | 0x01C | TIE_EN[255:224] | Input tie enable bits [255:224] | + * | 0x020 | TIE_VAL[31:0] | Input tie value bits [31:0] | + * | 0x024 | TIE_VAL[63:32] | Input tie value bits [63:32] | + * | 0x028 | TIE_VAL[95:64] | Input tie value bits [95:64] | + * | 0x02C | TIE_VAL[127:96] | Input tie value bits [127:96] | + * | 0x030 | TIE_VAL[159:128] | Input tie value bits [159:128] | + * | 0x034 | TIE_VAL[191:160] | Input tie value bits [191:160] | + * | 0x038 | TIE_VAL[223:192] | Input tie value bits [223:192] | + * | 0x03C | TIE_VAL[255:224] | Input tie value bits [255:224] | + * + * @note Function which input tie high by default + * + * | Name |Description | + * |---------------|---------------------------------------| + * | SPI0_ARB | Arbitration function of SPI master 0 | + * | SPI1_ARB | Arbitration function of SPI master 1 | + * + * Tie high means the SPI Arbitration input is 1 + * + */ +typedef struct _fpioa_tie +{ + uint32_t en[FUNC_MAX / 32]; + /*!< FPIOA GPIO multiplexer tie enable array */ + uint32_t val[FUNC_MAX / 32]; + /*!< FPIOA GPIO multiplexer tie value array */ +} __attribute__((packed, aligned(4))) fpioa_tie_t; + +/** + * @brief FPIOA Object + * + * FPIOA Object have 48 IO pin object and 256 bit input tie bits. + * All SPI arbitration signal will tie high by default. + * + * @note FPIOA IO Pin RAM Layout + * + * | Address | Name |Description | + * |-----------|----------|--------------------------------| + * | 0x000 | PAD0 | FPIOA GPIO multiplexer io 0 | + * | 0x004 | PAD1 | FPIOA GPIO multiplexer io 1 | + * | 0x008 | PAD2 | FPIOA GPIO multiplexer io 2 | + * | 0x00C | PAD3 | FPIOA GPIO multiplexer io 3 | + * | 0x010 | PAD4 | FPIOA GPIO multiplexer io 4 | + * | 0x014 | PAD5 | FPIOA GPIO multiplexer io 5 | + * | 0x018 | PAD6 | FPIOA GPIO multiplexer io 6 | + * | 0x01C | PAD7 | FPIOA GPIO multiplexer io 7 | + * | 0x020 | PAD8 | FPIOA GPIO multiplexer io 8 | + * | 0x024 | PAD9 | FPIOA GPIO multiplexer io 9 | + * | 0x028 | PAD10 | FPIOA GPIO multiplexer io 10 | + * | 0x02C | PAD11 | FPIOA GPIO multiplexer io 11 | + * | 0x030 | PAD12 | FPIOA GPIO multiplexer io 12 | + * | 0x034 | PAD13 | FPIOA GPIO multiplexer io 13 | + * | 0x038 | PAD14 | FPIOA GPIO multiplexer io 14 | + * | 0x03C | PAD15 | FPIOA GPIO multiplexer io 15 | + * | 0x040 | PAD16 | FPIOA GPIO multiplexer io 16 | + * | 0x044 | PAD17 | FPIOA GPIO multiplexer io 17 | + * | 0x048 | PAD18 | FPIOA GPIO multiplexer io 18 | + * | 0x04C | PAD19 | FPIOA GPIO multiplexer io 19 | + * | 0x050 | PAD20 | FPIOA GPIO multiplexer io 20 | + * | 0x054 | PAD21 | FPIOA GPIO multiplexer io 21 | + * | 0x058 | PAD22 | FPIOA GPIO multiplexer io 22 | + * | 0x05C | PAD23 | FPIOA GPIO multiplexer io 23 | + * | 0x060 | PAD24 | FPIOA GPIO multiplexer io 24 | + * | 0x064 | PAD25 | FPIOA GPIO multiplexer io 25 | + * | 0x068 | PAD26 | FPIOA GPIO multiplexer io 26 | + * | 0x06C | PAD27 | FPIOA GPIO multiplexer io 27 | + * | 0x070 | PAD28 | FPIOA GPIO multiplexer io 28 | + * | 0x074 | PAD29 | FPIOA GPIO multiplexer io 29 | + * | 0x078 | PAD30 | FPIOA GPIO multiplexer io 30 | + * | 0x07C | PAD31 | FPIOA GPIO multiplexer io 31 | + * | 0x080 | PAD32 | FPIOA GPIO multiplexer io 32 | + * | 0x084 | PAD33 | FPIOA GPIO multiplexer io 33 | + * | 0x088 | PAD34 | FPIOA GPIO multiplexer io 34 | + * | 0x08C | PAD35 | FPIOA GPIO multiplexer io 35 | + * | 0x090 | PAD36 | FPIOA GPIO multiplexer io 36 | + * | 0x094 | PAD37 | FPIOA GPIO multiplexer io 37 | + * | 0x098 | PAD38 | FPIOA GPIO multiplexer io 38 | + * | 0x09C | PAD39 | FPIOA GPIO multiplexer io 39 | + * | 0x0A0 | PAD40 | FPIOA GPIO multiplexer io 40 | + * | 0x0A4 | PAD41 | FPIOA GPIO multiplexer io 41 | + * | 0x0A8 | PAD42 | FPIOA GPIO multiplexer io 42 | + * | 0x0AC | PAD43 | FPIOA GPIO multiplexer io 43 | + * | 0x0B0 | PAD44 | FPIOA GPIO multiplexer io 44 | + * | 0x0B4 | PAD45 | FPIOA GPIO multiplexer io 45 | + * | 0x0B8 | PAD46 | FPIOA GPIO multiplexer io 46 | + * | 0x0BC | PAD47 | FPIOA GPIO multiplexer io 47 | + * + */ +typedef struct _fpioa +{ + fpioa_io_config_t io[FPIOA_NUM_IO]; + /*!< FPIOA GPIO multiplexer io array */ + fpioa_tie_t tie; + /*!< FPIOA GPIO multiplexer tie */ +} __attribute__((packed, aligned(4))) fpioa_t; + +/** + * @brief FPIOA object instanse + */ +extern volatile fpioa_t *const fpioa; + +/** + * @brief Initialize FPIOA user custom default settings + * + * @note This function will set all FPIOA pad registers to user-defined + * values from kconfig + * + * @return result + * - 0 Success + * - Other Fail + */ +int 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, fpioa_io_config_t *cfg); + +/** + * @brief Set IO configuration + * + * @param[in] number The IO number + * @param[in] cfg Pointer to struct of IO configuration for specified IO + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io(int number, fpioa_io_config_t *cfg); + +/** + * @brief Set IO configuration with function number + * + * @note The default IO configuration which bind to function number will + * set automatically + * + * @param[in] number The IO number + * @param[in] function The function enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_function_raw(int number, fpioa_function_t function); + +/** + * @brief Set only IO configuration with function number + * + * @note The default IO configuration which bind to function number will + * set automatically + * + * @param[in] number The IO number + * @param[in] function The function enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_function(int number, fpioa_function_t function); + +/** + * @brief Set tie enable to function + * + * @param[in] function The function enum number + * @param[in] enable Tie enable to set, 1 is enable, 0 is disable + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_tie_enable(fpioa_function_t function, int enable); + +/** + * @brief Set tie value to function + * + * @param[in] function The function enum number + * @param[in] value Tie value to set, 1 is HIGH, 0 is LOW + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_tie_value(fpioa_function_t function, int value); + +/** + * @brief Set IO pull function + * + * @param[in] number The IO number + * @param[in] pull The pull enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io_pull(int number, fpioa_pull_t pull); + +/** + * @brief Get IO pull function + * + * @param[in] number The IO number + * + * @return result + * - -1 Fail + * - Other The pull enum number + */ +int fpioa_get_io_pull(int number); + +/** + * @brief Set IO driving + * + * @param[in] number The IO number + * @param[in] driving The driving enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io_driving(int number, fpioa_driving_t driving); + +/** + * @brief Get IO driving + * + * @param[in] number The IO number + * + * @return result + * - -1 Fail + * - Other The driving enum number + */ +int fpioa_get_io_driving(int number); + +/** + * @brief Get IO by function + * + * @param[in] function The function enum number + * + * @return result + * - -1 Fail + * - Other The IO number + */ +int fpioa_get_io_by_function(fpioa_function_t function); + +/** + * @brief Set IO slew rate control + * + * @param[in] number The IO number + * @param[in] sl_value Enable slew rate. 0: disable 1:enable + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_sl(int number, uint8_t sl_enable); + +/** + * @brief Set IO schmitt trigger + * + * @param[in] number The IO number + * @param[in] st_enable Enable schmitt trigger. 0: disable 1:enable + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_st(int number, uint8_t st_enable); + +/** + * @brief Set IO output invert enable + * + * @param[in] number The IO number + * @param[in] inv_enable Enable output invert. 0: disable 1:enable + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_oe_inv(int number, uint8_t inv_enable); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_FPIOA_H */ diff --git a/Kboot/src/bootloader_hi/include/gpiohs.h b/Kboot/src/bootloader_hi/include/gpiohs.h new file mode 100644 index 0000000..f4bad1c --- /dev/null +++ b/Kboot/src/bootloader_hi/include/gpiohs.h @@ -0,0 +1,256 @@ +/* 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 +#include +#include "platform.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 */ + +typedef enum _gpio_drive_mode +{ + GPIO_DM_INPUT, + GPIO_DM_INPUT_PULL_DOWN, + GPIO_DM_INPUT_PULL_UP, + GPIO_DM_OUTPUT, +} gpio_drive_mode_t; + +typedef enum _gpio_pin_edge +{ + GPIO_PE_NONE, + GPIO_PE_FALLING, + GPIO_PE_RISING, + GPIO_PE_BOTH, + GPIO_PE_LOW, + GPIO_PE_HIGH = 8, +} gpio_pin_edge_t; + +typedef enum _gpio_pin_value +{ + GPIO_PV_LOW, + GPIO_PV_HIGH +} gpio_pin_value_t; + +/** + * @brief GPIO bits raw object + */ +typedef struct _gpiohs_raw +{ + /* Address offset 0x00 */ + uint32_t input_val; + /* Address offset 0x04 */ + uint32_t input_en; + /* Address offset 0x08 */ + uint32_t output_en; + /* Address offset 0x0c */ + uint32_t output_val; + /* Address offset 0x10 */ + uint32_t pullup_en; + /* Address offset 0x14 */ + uint32_t drive; + /* Address offset 0x18 */ + uint32_t rise_ie; + /* Address offset 0x1c */ + uint32_t rise_ip; + /* Address offset 0x20 */ + uint32_t fall_ie; + /* Address offset 0x24 */ + uint32_t fall_ip; + /* Address offset 0x28 */ + uint32_t high_ie; + /* Address offset 0x2c */ + uint32_t high_ip; + /* Address offset 0x30 */ + uint32_t low_ie; + /* Address offset 0x34 */ + uint32_t low_ip; + /* Address offset 0x38 */ + uint32_t iof_en; + /* Address offset 0x3c */ + uint32_t iof_sel; + /* Address offset 0x40 */ + uint32_t output_xor; +} __attribute__((packed, aligned(4))) gpiohs_raw_t; + +/** + * @brief GPIO bits object + */ +typedef struct _gpiohs_bits +{ + uint32_t b0 : 1; + uint32_t b1 : 1; + uint32_t b2 : 1; + uint32_t b3 : 1; + uint32_t b4 : 1; + uint32_t b5 : 1; + uint32_t b6 : 1; + uint32_t b7 : 1; + uint32_t b8 : 1; + uint32_t b9 : 1; + uint32_t b10 : 1; + uint32_t b11 : 1; + uint32_t b12 : 1; + uint32_t b13 : 1; + uint32_t b14 : 1; + uint32_t b15 : 1; + uint32_t b16 : 1; + uint32_t b17 : 1; + uint32_t b18 : 1; + uint32_t b19 : 1; + uint32_t b20 : 1; + uint32_t b21 : 1; + uint32_t b22 : 1; + uint32_t b23 : 1; + uint32_t b24 : 1; + uint32_t b25 : 1; + uint32_t b26 : 1; + uint32_t b27 : 1; + uint32_t b28 : 1; + uint32_t b29 : 1; + uint32_t b30 : 1; + uint32_t b31 : 1; +} __attribute__((packed, aligned(4))) gpiohs_bits_t; + +/** + * @brief GPIO bits multi access union + */ +typedef union _gpiohs_u32 +{ + /* 32x1 bit mode */ + uint32_t u32[1]; + /* 16x2 bit mode */ + uint16_t u16[2]; + /* 8x4 bit mode */ + uint8_t u8[4]; + /* 1 bit mode */ + gpiohs_bits_t bits; +} __attribute__((packed, aligned(4))) gpiohs_u32_t; + +/** + * @brief GPIO object + * + * The GPIO controller is a peripheral device mapped in the + * internal memory map, discoverable in the Configuration String. + * It is responsible for low-level configuration of the actual + * GPIO pads on the device (direction, pull up-enable, and drive + * value), as well as selecting between various sources of the + * controls for these signals. The GPIO controller allows seperate + * configuration of each of N GPIO bits. + * + * Once the interrupt is pending, it will remain set until a 1 is + * written to the *_ip register at that bit. + */ + +typedef struct _gpiohs +{ + /* Address offset 0x00, Input Values */ + gpiohs_u32_t input_val; + /* Address offset 0x04, Input enable */ + gpiohs_u32_t input_en; + /* Address offset 0x08, Output enable */ + gpiohs_u32_t output_en; + /* Address offset 0x0c, Onput Values */ + gpiohs_u32_t output_val; + /* Address offset 0x10, Internal Pull-Ups enable */ + gpiohs_u32_t pullup_en; + /* Address offset 0x14, Drive Strength */ + gpiohs_u32_t drive; + /* Address offset 0x18, Rise interrupt enable */ + gpiohs_u32_t rise_ie; + /* Address offset 0x1c, Rise interrupt pending */ + gpiohs_u32_t rise_ip; + /* Address offset 0x20, Fall interrupt enable */ + gpiohs_u32_t fall_ie; + /* Address offset 0x24, Fall interrupt pending */ + gpiohs_u32_t fall_ip; + /* Address offset 0x28, High interrupt enable */ + gpiohs_u32_t high_ie; + /* Address offset 0x2c, High interrupt pending */ + gpiohs_u32_t high_ip; + /* Address offset 0x30, Low interrupt enable */ + gpiohs_u32_t low_ie; + /* Address offset 0x34, Low interrupt pending */ + gpiohs_u32_t low_ip; + /* Address offset 0x38, HW I/O Function enable */ + gpiohs_u32_t iof_en; + /* Address offset 0x3c, HW I/O Function select */ + gpiohs_u32_t iof_sel; + /* Address offset 0x40, Output XOR (invert) */ + gpiohs_u32_t output_xor; +} __attribute__((packed, aligned(4))) gpiohs_t; + +/** + * @brief GPIO High-speed object instanse + */ +extern volatile gpiohs_t *const gpiohs; + +/** + * @brief Set Gpiohs drive mode + * + * @param[in] pin Gpiohs pin + * @param[in] mode Gpiohs pin drive mode + */ +void gpiohs_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode); + +/** + * @brief Get Gpiohs pin value + * + * @param[in] pin Gpiohs pin + * @return Pin value + * + * - GPIO_PV_Low Gpiohs pin low + * - GPIO_PV_High Gpiohs pin high + */ +gpio_pin_value_t gpiohs_get_pin(uint8_t pin); + +/** + * @brief Set Gpiohs pin value + * + * @param[in] pin Gpiohs pin + * @param[in] value Gpiohs pin value + */ +void gpiohs_set_pin(uint8_t pin, gpio_pin_value_t value); + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_GPIOHS_H */ diff --git a/Kboot/src/bootloader_hi/include/platform.h b/Kboot/src/bootloader_hi/include/platform.h new file mode 100644 index 0000000..a2800a9 --- /dev/null +++ b/Kboot/src/bootloader_hi/include/platform.h @@ -0,0 +1,98 @@ +/* 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 */ diff --git a/Kboot/src/bootloader_hi/include/sha256.h b/Kboot/src/bootloader_hi/include/sha256.h new file mode 100644 index 0000000..4210e54 --- /dev/null +++ b/Kboot/src/bootloader_hi/include/sha256.h @@ -0,0 +1,130 @@ +/* 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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ENABLE_SHA (0x1) +#define SHA256_BIG_ENDIAN (0x1) + +#define SHA256_HASH_LEN 32 +#define SHA256_HASH_WORDS 8 +#define SHA256_BLOCK_LEN 64L + +typedef struct _sha_num_reg +{ + /* The total amount of data calculated by SHA256 is set by this register, and the smallest unit is 512bit. */ + uint32_t sha_data_cnt : 16; + /* currently calculated block number. 512bit=1block*/ + uint32_t sha_data_num : 16; +} __attribute__((packed, aligned(4))) sha_num_reg_t; + +typedef struct _sha_function_reg_0 +{ + /* write:SHA256 enable register. read:Calculation completed flag */ + uint32_t sha_en : 1; + uint32_t reserved00 : 7; + /* SHA256 calculation overflow flag */ + uint32_t sha_overflow : 1; + uint32_t reserved01 : 7; + /* Endian setting; b'0:little endian b'1:big endian */ + uint32_t sha_endian : 1; + uint32_t reserved02 : 15; +} __attribute__((packed, aligned(4))) sha_function_reg_0_t; + +typedef struct _sha_function_reg_1 +{ + /* Sha and DMA handshake signals enable.b'1:enable;b'0:disable */ + uint32_t dma_en : 1; + uint32_t reserved10 : 7; + /* b'1:sha256 fifo is full; b'0:not full */ + uint32_t fifo_in_full : 1; + uint32_t reserved11 : 23; +} __attribute__((packed, aligned(4))) sha_function_reg_1_t; + +typedef struct _sha256 +{ + /* Calculated sha256 return value. */ + uint32_t sha_result[8]; + /* SHA256 input data from this register. */ + uint32_t sha_data_in1; + uint32_t reselved0; + sha_num_reg_t sha_num_reg; + sha_function_reg_0_t sha_function_reg_0; + uint32_t reserved1; + sha_function_reg_1_t sha_function_reg_1; +} __attribute__((packed, aligned(4))) sha256_t; + +typedef struct _sha256_context +{ + size_t total_len; + size_t buffer_len; + union + { + uint32_t words[16]; + uint8_t bytes[64]; + } buffer; +} sha256_context_t; + +/** + * @brief Init SHA256 calculation context + * + * @param[in] context SHA256 context object + * + */ +void sha256_init(sha256_context_t *context, size_t input_len); + +/** + * @brief Called repeatedly with chunks of the message to be hashed + * + * @param[in] context SHA256 context object + * @param[in] data_buf data chunk to be hashed + * @param[in] buf_len length of data chunk + * + */ +void sha256_update(sha256_context_t *context, const void *input, size_t input_len); + +/** + * @brief Finish SHA256 hash process, output the result. + * + * @param[in] context SHA256 context object + * @param[out] output The buffer where SHA256 hash will be output + * + */ +void sha256_final(sha256_context_t *context, uint8_t *output); + +/** + * @brief Simple SHA256 hash once. + * + * @param[in] data Data will be hashed + * @param[in] data_len Data length + * @param[out] output Output buffer + * + */ +void sha256_hard_calculate(const uint8_t *input, size_t input_len, uint8_t *output); + + +int usleep(uint64_t usec); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Kboot/src/bootloader_hi/include/spi.h b/Kboot/src/bootloader_hi/include/spi.h new file mode 100644 index 0000000..2646cf8 --- /dev/null +++ b/Kboot/src/bootloader_hi/include/spi.h @@ -0,0 +1,123 @@ +/* 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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _spi +{ + /* SPI Control Register 0 (0x00)*/ + volatile uint32_t ctrlr0; + /* SPI Control Register 1 (0x04)*/ + volatile uint32_t ctrlr1; + /* SPI Enable Register (0x08)*/ + volatile uint32_t ssienr; + /* SPI Microwire Control Register (0x0c)*/ + volatile uint32_t mwcr; + /* SPI Slave Enable Register (0x10)*/ + volatile uint32_t ser; + /* SPI Baud Rate Select (0x14)*/ + volatile uint32_t baudr; + /* SPI Transmit FIFO Threshold Level (0x18)*/ + volatile uint32_t txftlr; + /* SPI Receive FIFO Threshold Level (0x1c)*/ + volatile uint32_t rxftlr; + /* SPI Transmit FIFO Level Register (0x20)*/ + volatile uint32_t txflr; + /* SPI Receive FIFO Level Register (0x24)*/ + volatile uint32_t rxflr; + /* SPI Status Register (0x28)*/ + volatile uint32_t sr; + /* SPI Interrupt Mask Register (0x2c)*/ + volatile uint32_t imr; + /* SPI Interrupt Status Register (0x30)*/ + volatile uint32_t isr; + /* SPI Raw Interrupt Status Register (0x34)*/ + volatile uint32_t risr; + /* SPI Transmit FIFO Overflow Interrupt Clear Register (0x38)*/ + volatile uint32_t txoicr; + /* SPI Receive FIFO Overflow Interrupt Clear Register (0x3c)*/ + volatile uint32_t rxoicr; + /* SPI Receive FIFO Underflow Interrupt Clear Register (0x40)*/ + volatile uint32_t rxuicr; + /* SPI Multi-Master Interrupt Clear Register (0x44)*/ + volatile uint32_t msticr; + /* SPI Interrupt Clear Register (0x48)*/ + volatile uint32_t icr; + /* SPI DMA Control Register (0x4c)*/ + volatile uint32_t dmacr; + /* SPI DMA Transmit Data Level (0x50)*/ + volatile uint32_t dmatdlr; + /* SPI DMA Receive Data Level (0x54)*/ + volatile uint32_t dmardlr; + /* SPI Identification Register (0x58)*/ + volatile uint32_t idr; + /* SPI DWC_ssi component version (0x5c)*/ + volatile uint32_t ssic_version_id; + /* SPI Data Register 0-36 (0x60 -- 0xec)*/ + volatile uint32_t dr[36]; + /* SPI RX Sample Delay Register (0xf0)*/ + volatile uint32_t rx_sample_delay; + /* SPI SPI Control Register (0xf4)*/ + volatile uint32_t spi_ctrlr0; + /* reserved (0xf8)*/ + volatile uint32_t resv; + /* SPI XIP Mode bits (0xfc)*/ + volatile uint32_t xip_mode_bits; + /* SPI XIP INCR transfer opcode (0x100)*/ + volatile uint32_t xip_incr_inst; + /* SPI XIP WRAP transfer opcode (0x104)*/ + volatile uint32_t xip_wrap_inst; + /* SPI XIP Control Register (0x108)*/ + volatile uint32_t xip_ctrl; + /* SPI XIP Slave Enable Register (0x10c)*/ + volatile uint32_t xip_ser; + /* SPI XIP Receive FIFO Overflow Interrupt Clear Register (0x110)*/ + volatile uint32_t xrxoicr; + /* SPI XIP time out register for continuous transfers (0x114)*/ + volatile uint32_t xip_cnt_time_out; + volatile uint32_t endian; +} __attribute__((packed, aligned(4))) spi_t; +/* clang-format on */ + +typedef enum _spi_work_mode +{ + SPI_WORK_MODE_0, + SPI_WORK_MODE_1, + SPI_WORK_MODE_2, + SPI_WORK_MODE_3, +} spi_work_mode_t; + +typedef enum _spi_frame_format +{ + SPI_FF_STANDARD, + SPI_FF_DUAL, + SPI_FF_QUAD, + SPI_FF_OCTAL +} spi_frame_format_t; + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_SPI_H */ diff --git a/Kboot/src/bootloader_hi/include/sysctl.h b/Kboot/src/bootloader_hi/include/sysctl.h new file mode 100644 index 0000000..b37bd64 --- /dev/null +++ b/Kboot/src/bootloader_hi/include/sysctl.h @@ -0,0 +1,886 @@ +/* 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 +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define DEFAULT_CPU_CLOCK 390000000 + + +/** + * @brief System controller register + * + * @note System controller register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | git_id | Git short commit id | + * | 0x04 | clk_freq | System clock base frequency | + * | 0x08 | pll0 | PLL0 controller | + * | 0x0c | pll1 | PLL1 controller | + * | 0x10 | pll2 | PLL2 controller | + * | 0x14 | resv5 | Reserved | + * | 0x18 | pll_lock | PLL lock tester | + * | 0x1c | rom_error | AXI ROM detector | + * | 0x20 | clk_sel0 | Clock select controller0 | + * | 0x24 | clk_sel1 | Clock select controller1 | + * | 0x28 | clk_en_cent | Central clock enable | + * | 0x2c | clk_en_peri | Peripheral clock enable | + * | 0x30 | soft_reset | Soft reset ctrl | + * | 0x34 | peri_reset | Peripheral reset controller | + * | 0x38 | clk_th0 | Clock threshold controller 0 | + * | 0x3c | clk_th1 | Clock threshold controller 1 | + * | 0x40 | clk_th2 | Clock threshold controller 2 | + * | 0x44 | clk_th3 | Clock threshold controller 3 | + * | 0x48 | clk_th4 | Clock threshold controller 4 | + * | 0x4c | clk_th5 | Clock threshold controller 5 | + * | 0x50 | clk_th6 | Clock threshold controller 6 | + * | 0x54 | misc | Miscellaneous controller | + * | 0x58 | peri | Peripheral controller | + * | 0x5c | spi_sleep | SPI sleep controller | + * | 0x60 | reset_status | Reset source status | + * | 0x64 | dma_sel0 | DMA handshake selector | + * | 0x68 | dma_sel1 | DMA handshake selector | + * | 0x6c | power_sel | IO Power Mode Select controller | + * | 0x70 | resv28 | Reserved | + * | 0x74 | resv29 | Reserved | + * | 0x78 | resv30 | Reserved | + * | 0x7c | resv31 | Reserved | + * + */ + +typedef enum _sysctl_pll_t +{ + SYSCTL_PLL0, + SYSCTL_PLL1, + SYSCTL_PLL2, + SYSCTL_PLL_MAX +} sysctl_pll_t; + +typedef enum _sysctl_clock_source_t +{ + SYSCTL_SOURCE_IN0, + SYSCTL_SOURCE_PLL0, + SYSCTL_SOURCE_PLL1, + SYSCTL_SOURCE_PLL2, + SYSCTL_SOURCE_ACLK, + SYSCTL_SOURCE_MAX +} sysctl_clock_source_t; + +typedef enum _sysctl_dma_channel_t +{ + SYSCTL_DMA_CHANNEL_0, + SYSCTL_DMA_CHANNEL_1, + SYSCTL_DMA_CHANNEL_2, + SYSCTL_DMA_CHANNEL_3, + SYSCTL_DMA_CHANNEL_4, + SYSCTL_DMA_CHANNEL_5, + SYSCTL_DMA_CHANNEL_MAX +} sysctl_dma_channel_t; + +typedef enum _sysctl_dma_select_t +{ + SYSCTL_DMA_SELECT_SSI0_RX_REQ, + SYSCTL_DMA_SELECT_SSI0_TX_REQ, + SYSCTL_DMA_SELECT_SSI1_RX_REQ, + SYSCTL_DMA_SELECT_SSI1_TX_REQ, + SYSCTL_DMA_SELECT_SSI2_RX_REQ, + SYSCTL_DMA_SELECT_SSI2_TX_REQ, + SYSCTL_DMA_SELECT_SSI3_RX_REQ, + SYSCTL_DMA_SELECT_SSI3_TX_REQ, + SYSCTL_DMA_SELECT_I2C0_RX_REQ, + SYSCTL_DMA_SELECT_I2C0_TX_REQ, + SYSCTL_DMA_SELECT_I2C1_RX_REQ, + SYSCTL_DMA_SELECT_I2C1_TX_REQ, + SYSCTL_DMA_SELECT_I2C2_RX_REQ, + SYSCTL_DMA_SELECT_I2C2_TX_REQ, + SYSCTL_DMA_SELECT_UART1_RX_REQ, + SYSCTL_DMA_SELECT_UART1_TX_REQ, + SYSCTL_DMA_SELECT_UART2_RX_REQ, + SYSCTL_DMA_SELECT_UART2_TX_REQ, + SYSCTL_DMA_SELECT_UART3_RX_REQ, + SYSCTL_DMA_SELECT_UART3_TX_REQ, + SYSCTL_DMA_SELECT_AES_REQ, + SYSCTL_DMA_SELECT_SHA_RX_REQ, + SYSCTL_DMA_SELECT_AI_RX_REQ, + SYSCTL_DMA_SELECT_FFT_RX_REQ, + SYSCTL_DMA_SELECT_FFT_TX_REQ, + SYSCTL_DMA_SELECT_I2S0_TX_REQ, + SYSCTL_DMA_SELECT_I2S0_RX_REQ, + SYSCTL_DMA_SELECT_I2S1_TX_REQ, + SYSCTL_DMA_SELECT_I2S1_RX_REQ, + SYSCTL_DMA_SELECT_I2S2_TX_REQ, + SYSCTL_DMA_SELECT_I2S2_RX_REQ, + SYSCTL_DMA_SELECT_I2S0_BF_DIR_REQ, + SYSCTL_DMA_SELECT_I2S0_BF_VOICE_REQ, + SYSCTL_DMA_SELECT_MAX +} sysctl_dma_select_t; + +/** + * @brief System controller clock id + */ +typedef enum _sysctl_clock_t +{ + SYSCTL_CLOCK_PLL0, + SYSCTL_CLOCK_PLL1, + SYSCTL_CLOCK_PLL2, + SYSCTL_CLOCK_CPU, + SYSCTL_CLOCK_SRAM0, + SYSCTL_CLOCK_SRAM1, + SYSCTL_CLOCK_APB0, + SYSCTL_CLOCK_APB1, + SYSCTL_CLOCK_APB2, + SYSCTL_CLOCK_ROM, + SYSCTL_CLOCK_DMA, + SYSCTL_CLOCK_AI, + SYSCTL_CLOCK_DVP, + SYSCTL_CLOCK_FFT, + SYSCTL_CLOCK_GPIO, + SYSCTL_CLOCK_SPI0, + SYSCTL_CLOCK_SPI1, + SYSCTL_CLOCK_SPI2, + SYSCTL_CLOCK_SPI3, + SYSCTL_CLOCK_I2S0, + SYSCTL_CLOCK_I2S1, + SYSCTL_CLOCK_I2S2, + SYSCTL_CLOCK_I2C0, + SYSCTL_CLOCK_I2C1, + SYSCTL_CLOCK_I2C2, + SYSCTL_CLOCK_UART1, + SYSCTL_CLOCK_UART2, + SYSCTL_CLOCK_UART3, + SYSCTL_CLOCK_AES, + SYSCTL_CLOCK_FPIOA, + SYSCTL_CLOCK_TIMER0, + SYSCTL_CLOCK_TIMER1, + SYSCTL_CLOCK_TIMER2, + SYSCTL_CLOCK_WDT0, + SYSCTL_CLOCK_WDT1, + SYSCTL_CLOCK_SHA, + SYSCTL_CLOCK_OTP, + SYSCTL_CLOCK_RTC, + SYSCTL_CLOCK_ACLK = 40, + SYSCTL_CLOCK_HCLK, + SYSCTL_CLOCK_IN0, + SYSCTL_CLOCK_MAX +} sysctl_clock_t; + +/** + * @brief System controller clock select id + */ +typedef enum _sysctl_clock_select_t +{ + SYSCTL_CLOCK_SELECT_PLL0_BYPASS, + SYSCTL_CLOCK_SELECT_PLL1_BYPASS, + SYSCTL_CLOCK_SELECT_PLL2_BYPASS, + SYSCTL_CLOCK_SELECT_PLL2, + SYSCTL_CLOCK_SELECT_ACLK, + SYSCTL_CLOCK_SELECT_SPI3, + SYSCTL_CLOCK_SELECT_TIMER0, + SYSCTL_CLOCK_SELECT_TIMER1, + SYSCTL_CLOCK_SELECT_TIMER2, + SYSCTL_CLOCK_SELECT_SPI3_SAMPLE, + SYSCTL_CLOCK_SELECT_MAX = 11 +} sysctl_clock_select_t; + +/** + * @brief System controller clock threshold id + */ +typedef enum _sysctl_threshold_t +{ + SYSCTL_THRESHOLD_ACLK, + SYSCTL_THRESHOLD_APB0, + SYSCTL_THRESHOLD_APB1, + SYSCTL_THRESHOLD_APB2, + SYSCTL_THRESHOLD_SRAM0, + SYSCTL_THRESHOLD_SRAM1, + SYSCTL_THRESHOLD_AI, + SYSCTL_THRESHOLD_DVP, + SYSCTL_THRESHOLD_ROM, + SYSCTL_THRESHOLD_SPI0, + SYSCTL_THRESHOLD_SPI1, + SYSCTL_THRESHOLD_SPI2, + SYSCTL_THRESHOLD_SPI3, + SYSCTL_THRESHOLD_TIMER0, + SYSCTL_THRESHOLD_TIMER1, + SYSCTL_THRESHOLD_TIMER2, + SYSCTL_THRESHOLD_I2S0, + SYSCTL_THRESHOLD_I2S1, + SYSCTL_THRESHOLD_I2S2, + SYSCTL_THRESHOLD_I2S0_M, + SYSCTL_THRESHOLD_I2S1_M, + SYSCTL_THRESHOLD_I2S2_M, + SYSCTL_THRESHOLD_I2C0, + SYSCTL_THRESHOLD_I2C1, + SYSCTL_THRESHOLD_I2C2, + SYSCTL_THRESHOLD_WDT0, + SYSCTL_THRESHOLD_WDT1, + SYSCTL_THRESHOLD_MAX = 28 +} sysctl_threshold_t; + +/** + * @brief System controller reset control id + */ +typedef enum _sysctl_reset_t +{ + SYSCTL_RESET_SOC, + SYSCTL_RESET_ROM, + SYSCTL_RESET_DMA, + SYSCTL_RESET_AI, + SYSCTL_RESET_DVP, + SYSCTL_RESET_FFT, + SYSCTL_RESET_GPIO, + SYSCTL_RESET_SPI0, + SYSCTL_RESET_SPI1, + SYSCTL_RESET_SPI2, + SYSCTL_RESET_SPI3, + SYSCTL_RESET_I2S0, + SYSCTL_RESET_I2S1, + SYSCTL_RESET_I2S2, + SYSCTL_RESET_I2C0, + SYSCTL_RESET_I2C1, + SYSCTL_RESET_I2C2, + SYSCTL_RESET_UART1, + SYSCTL_RESET_UART2, + SYSCTL_RESET_UART3, + SYSCTL_RESET_AES, + SYSCTL_RESET_FPIOA, + SYSCTL_RESET_TIMER0, + SYSCTL_RESET_TIMER1, + SYSCTL_RESET_TIMER2, + SYSCTL_RESET_WDT0, + SYSCTL_RESET_WDT1, + SYSCTL_RESET_SHA, + SYSCTL_RESET_RTC, + SYSCTL_RESET_MAX = 31 +} sysctl_reset_t; + +/** + * @brief System controller power bank id + */ +typedef enum _sysctl_power_bank +{ + SYSCTL_POWER_BANK0, + SYSCTL_POWER_BANK1, + SYSCTL_POWER_BANK2, + SYSCTL_POWER_BANK3, + SYSCTL_POWER_BANK4, + SYSCTL_POWER_BANK5, + SYSCTL_POWER_BANK6, + SYSCTL_POWER_BANK7, + SYSCTL_POWER_BANK_MAX, +} sysctl_power_bank_t; + +/** + * @brief System controller reset control id + */ +typedef enum _sysctl_io_power_mode +{ + SYSCTL_POWER_V33, + SYSCTL_POWER_V18 +} sysctl_io_power_mode_t; + +/** + * @brief System reset status + */ +typedef enum _sysctl_reset_enum_status +{ + SYSCTL_RESET_STATUS_HARD, + SYSCTL_RESET_STATUS_SOFT, + SYSCTL_RESET_STATUS_WDT0, + SYSCTL_RESET_STATUS_WDT1, + SYSCTL_RESET_STATUS_MAX, +} sysctl_reset_enum_status_t; + +/** + * @brief Git short commit id + * + * No. 0 Register (0x00) + */ +typedef struct _sysctl_git_id +{ + uint32_t git_id : 32; +} __attribute__((packed, aligned(4))) sysctl_git_id_t; + +/** + * @brief System clock base frequency + * + * No. 1 Register (0x04) + */ +typedef struct _sysctl_clk_freq +{ + uint32_t clk_freq : 32; +} __attribute__((packed, aligned(4))) sysctl_clk_freq_t; + +/** + * @brief PLL0 controller + * + * No. 2 Register (0x08) + */ +typedef struct _sysctl_pll0 +{ + uint32_t clkr0 : 4; + uint32_t clkf0 : 6; + uint32_t clkod0 : 4; + uint32_t bwadj0 : 6; + uint32_t pll_reset0 : 1; + uint32_t pll_pwrd0 : 1; + uint32_t pll_intfb0 : 1; + uint32_t pll_bypass0 : 1; + uint32_t pll_test0 : 1; + uint32_t pll_out_en0 : 1; + uint32_t pll_test_en : 1; + uint32_t reserved : 5; +} __attribute__((packed, aligned(4))) sysctl_pll0_t; + +/** + * @brief PLL1 controller + * + * No. 3 Register (0x0c) + */ +typedef struct _sysctl_pll1 +{ + uint32_t clkr1 : 4; + uint32_t clkf1 : 6; + uint32_t clkod1 : 4; + uint32_t bwadj1 : 6; + uint32_t pll_reset1 : 1; + uint32_t pll_pwrd1 : 1; + uint32_t pll_intfb1 : 1; + uint32_t pll_bypass1 : 1; + uint32_t pll_test1 : 1; + uint32_t pll_out_en1 : 1; + uint32_t reserved : 6; +} __attribute__((packed, aligned(4))) sysctl_pll1_t; + +/** + * @brief PLL2 controller + * + * No. 4 Register (0x10) + */ +typedef struct _sysctl_pll2 +{ + uint32_t clkr2 : 4; + uint32_t clkf2 : 6; + uint32_t clkod2 : 4; + uint32_t bwadj2 : 6; + uint32_t pll_reset2 : 1; + uint32_t pll_pwrd2 : 1; + uint32_t pll_intfb2 : 1; + uint32_t pll_bypass2 : 1; + uint32_t pll_test2 : 1; + uint32_t pll_out_en2 : 1; + uint32_t pll_ckin_sel2 : 2; + uint32_t reserved : 4; +} __attribute__((packed, aligned(4))) sysctl_pll2_t; + +/** + * @brief PLL lock tester + * + * No. 6 Register (0x18) + */ +typedef struct _sysctl_pll_lock +{ + uint32_t pll_lock0 : 2; + uint32_t pll_slip_clear0 : 1; + uint32_t test_clk_out0 : 1; + uint32_t reserved0 : 4; + uint32_t pll_lock1 : 2; + uint32_t pll_slip_clear1 : 1; + uint32_t test_clk_out1 : 1; + uint32_t reserved1 : 4; + uint32_t pll_lock2 : 2; + uint32_t pll_slip_clear2 : 1; + uint32_t test_clk_out2 : 1; + uint32_t reserved2 : 12; +} __attribute__((packed, aligned(4))) sysctl_pll_lock_t; + +/** + * @brief AXI ROM detector + * + * No. 7 Register (0x1c) + */ +typedef struct _sysctl_rom_error +{ + uint32_t rom_mul_error : 1; + uint32_t rom_one_error : 1; + uint32_t reserved : 30; +} __attribute__((packed, aligned(4))) sysctl_rom_error_t; + +/** + * @brief Clock select controller0 + * + * No. 8 Register (0x20) + */ +typedef struct _sysctl_clk_sel0 +{ + uint32_t aclk_sel : 1; + uint32_t aclk_divider_sel : 2; + uint32_t apb0_clk_sel : 3; + uint32_t apb1_clk_sel : 3; + uint32_t apb2_clk_sel : 3; + uint32_t spi3_clk_sel : 1; + uint32_t timer0_clk_sel : 1; + uint32_t timer1_clk_sel : 1; + uint32_t timer2_clk_sel : 1; + uint32_t reserved : 16; +} __attribute__((packed, aligned(4))) sysctl_clk_sel0_t; + +/** + * @brief Clock select controller1 + * + * No. 9 Register (0x24) + */ +typedef struct _sysctl_clk_sel1 +{ + uint32_t spi3_sample_clk_sel : 1; + uint32_t reserved0 : 30; + uint32_t reserved1 : 1; +} __attribute__((packed, aligned(4))) sysctl_clk_sel1_t; + +/** + * @brief Central clock enable + * + * No. 10 Register (0x28) + */ +typedef struct _sysctl_clk_en_cent +{ + uint32_t cpu_clk_en : 1; + uint32_t sram0_clk_en : 1; + uint32_t sram1_clk_en : 1; + uint32_t apb0_clk_en : 1; + uint32_t apb1_clk_en : 1; + uint32_t apb2_clk_en : 1; + uint32_t reserved : 26; +} __attribute__((packed, aligned(4))) sysctl_clk_en_cent_t; + +/** + * @brief Peripheral clock enable + * + * No. 11 Register (0x2c) + */ +typedef struct _sysctl_clk_en_peri +{ + uint32_t rom_clk_en : 1; + uint32_t dma_clk_en : 1; + uint32_t ai_clk_en : 1; + uint32_t dvp_clk_en : 1; + uint32_t fft_clk_en : 1; + uint32_t gpio_clk_en : 1; + uint32_t spi0_clk_en : 1; + uint32_t spi1_clk_en : 1; + uint32_t spi2_clk_en : 1; + uint32_t spi3_clk_en : 1; + uint32_t i2s0_clk_en : 1; + uint32_t i2s1_clk_en : 1; + uint32_t i2s2_clk_en : 1; + uint32_t i2c0_clk_en : 1; + uint32_t i2c1_clk_en : 1; + uint32_t i2c2_clk_en : 1; + uint32_t uart1_clk_en : 1; + uint32_t uart2_clk_en : 1; + uint32_t uart3_clk_en : 1; + uint32_t aes_clk_en : 1; + uint32_t fpioa_clk_en : 1; + uint32_t timer0_clk_en : 1; + uint32_t timer1_clk_en : 1; + uint32_t timer2_clk_en : 1; + uint32_t wdt0_clk_en : 1; + uint32_t wdt1_clk_en : 1; + uint32_t sha_clk_en : 1; + uint32_t otp_clk_en : 1; + uint32_t reserved : 1; + uint32_t rtc_clk_en : 1; + uint32_t reserved0 : 2; +} __attribute__((packed, aligned(4))) sysctl_clk_en_peri_t; + +/** + * @brief Soft reset ctrl + * + * No. 12 Register (0x30) + */ +typedef struct _sysctl_soft_reset +{ + uint32_t soft_reset : 1; + uint32_t reserved : 31; +} __attribute__((packed, aligned(4))) sysctl_soft_reset_t; + +/** + * @brief Peripheral reset controller + * + * No. 13 Register (0x34) + */ +typedef struct _sysctl_peri_reset +{ + uint32_t rom_reset : 1; + uint32_t dma_reset : 1; + uint32_t ai_reset : 1; + uint32_t dvp_reset : 1; + uint32_t fft_reset : 1; + uint32_t gpio_reset : 1; + uint32_t spi0_reset : 1; + uint32_t spi1_reset : 1; + uint32_t spi2_reset : 1; + uint32_t spi3_reset : 1; + uint32_t i2s0_reset : 1; + uint32_t i2s1_reset : 1; + uint32_t i2s2_reset : 1; + uint32_t i2c0_reset : 1; + uint32_t i2c1_reset : 1; + uint32_t i2c2_reset : 1; + uint32_t uart1_reset : 1; + uint32_t uart2_reset : 1; + uint32_t uart3_reset : 1; + uint32_t aes_reset : 1; + uint32_t fpioa_reset : 1; + uint32_t timer0_reset : 1; + uint32_t timer1_reset : 1; + uint32_t timer2_reset : 1; + uint32_t wdt0_reset : 1; + uint32_t wdt1_reset : 1; + uint32_t sha_reset : 1; + uint32_t reserved : 2; + uint32_t rtc_reset : 1; + uint32_t reserved0 : 2; +} __attribute__((packed, aligned(4))) sysctl_peri_reset_t; + +/** + * @brief Clock threshold controller 0 + * + * No. 14 Register (0x38) + */ +typedef struct _sysctl_clk_th0 +{ + uint32_t sram0_gclk_threshold : 4; + uint32_t sram1_gclk_threshold : 4; + uint32_t ai_gclk_threshold : 4; + uint32_t dvp_gclk_threshold : 4; + uint32_t rom_gclk_threshold : 4; + uint32_t reserved : 12; +} __attribute__((packed, aligned(4))) sysctl_clk_th0_t; + +/** + * @brief Clock threshold controller 1 + * + * No. 15 Register (0x3c) + */ +typedef struct _sysctl_clk_th1 +{ + uint32_t spi0_clk_threshold : 8; + uint32_t spi1_clk_threshold : 8; + uint32_t spi2_clk_threshold : 8; + uint32_t spi3_clk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th1_t; + +/** + * @brief Clock threshold controller 2 + * + * No. 16 Register (0x40) + */ +typedef struct _sysctl_clk_th2 +{ + uint32_t timer0_clk_threshold : 8; + uint32_t timer1_clk_threshold : 8; + uint32_t timer2_clk_threshold : 8; + uint32_t reserved : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th2_t; + +/** + * @brief Clock threshold controller 3 + * + * No. 17 Register (0x44) + */ +typedef struct _sysctl_clk_th3 +{ + uint32_t i2s0_clk_threshold : 16; + uint32_t i2s1_clk_threshold : 16; +} __attribute__((packed, aligned(4))) sysctl_clk_th3_t; + +/** + * @brief Clock threshold controller 4 + * + * No. 18 Register (0x48) + */ +typedef struct _sysctl_clk_th4 +{ + uint32_t i2s2_clk_threshold : 16; + uint32_t i2s0_mclk_threshold : 8; + uint32_t i2s1_mclk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th4_t; + +/** + * @brief Clock threshold controller 5 + * + * No. 19 Register (0x4c) + */ +typedef struct _sysctl_clk_th5 +{ + uint32_t i2s2_mclk_threshold : 8; + uint32_t i2c0_clk_threshold : 8; + uint32_t i2c1_clk_threshold : 8; + uint32_t i2c2_clk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th5_t; + +/** + * @brief Clock threshold controller 6 + * + * No. 20 Register (0x50) + */ +typedef struct _sysctl_clk_th6 +{ + uint32_t wdt0_clk_threshold : 8; + uint32_t wdt1_clk_threshold : 8; + uint32_t reserved0 : 8; + uint32_t reserved1 : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th6_t; + +/** + * @brief Miscellaneous controller + * + * No. 21 Register (0x54) + */ +typedef struct _sysctl_misc +{ + uint32_t debug_sel : 6; + uint32_t reserved0 : 4; + uint32_t spi_dvp_data_enable : 1; + uint32_t reserved1 : 21; +} __attribute__((packed, aligned(4))) sysctl_misc_t; + +/** + * @brief Peripheral controller + * + * No. 22 Register (0x58) + */ +typedef struct _sysctl_peri +{ + uint32_t timer0_pause : 1; + uint32_t timer1_pause : 1; + uint32_t timer2_pause : 1; + uint32_t timer3_pause : 1; + uint32_t timer4_pause : 1; + uint32_t timer5_pause : 1; + uint32_t timer6_pause : 1; + uint32_t timer7_pause : 1; + uint32_t timer8_pause : 1; + uint32_t timer9_pause : 1; + uint32_t timer10_pause : 1; + uint32_t timer11_pause : 1; + uint32_t spi0_xip_en : 1; + uint32_t spi1_xip_en : 1; + uint32_t spi2_xip_en : 1; + uint32_t spi3_xip_en : 1; + uint32_t spi0_clk_bypass : 1; + uint32_t spi1_clk_bypass : 1; + uint32_t spi2_clk_bypass : 1; + uint32_t i2s0_clk_bypass : 1; + uint32_t i2s1_clk_bypass : 1; + uint32_t i2s2_clk_bypass : 1; + uint32_t jtag_clk_bypass : 1; + uint32_t dvp_clk_bypass : 1; + uint32_t debug_clk_bypass : 1; + uint32_t reserved0 : 1; + uint32_t reserved1 : 6; +} __attribute__((packed, aligned(4))) sysctl_peri_t; + +/** + * @brief SPI sleep controller + * + * No. 23 Register (0x5c) + */ +typedef struct _sysctl_spi_sleep +{ + uint32_t ssi0_sleep : 1; + uint32_t ssi1_sleep : 1; + uint32_t ssi2_sleep : 1; + uint32_t ssi3_sleep : 1; + uint32_t reserved : 28; +} __attribute__((packed, aligned(4))) sysctl_spi_sleep_t; + +/** + * @brief Reset source status + * + * No. 24 Register (0x60) + */ +typedef struct _sysctl_reset_status +{ + uint32_t reset_sts_clr : 1; + uint32_t pin_reset_sts : 1; + uint32_t wdt0_reset_sts : 1; + uint32_t wdt1_reset_sts : 1; + uint32_t soft_reset_sts : 1; + uint32_t reserved : 27; +} __attribute__((packed, aligned(4))) sysctl_reset_status_t; + +/** + * @brief DMA handshake selector + * + * No. 25 Register (0x64) + */ +typedef struct _sysctl_dma_sel0 +{ + uint32_t dma_sel0 : 6; + uint32_t dma_sel1 : 6; + uint32_t dma_sel2 : 6; + uint32_t dma_sel3 : 6; + uint32_t dma_sel4 : 6; + uint32_t reserved : 2; +} __attribute__((packed, aligned(4))) sysctl_dma_sel0_t; + +/** + * @brief DMA handshake selector + * + * No. 26 Register (0x68) + */ +typedef struct _sysctl_dma_sel1 +{ + uint32_t dma_sel5 : 6; + uint32_t reserved : 26; +} __attribute__((packed, aligned(4))) sysctl_dma_sel1_t; + +/** + * @brief IO Power Mode Select controller + * + * No. 27 Register (0x6c) + */ +typedef struct _sysctl_power_sel +{ + uint32_t power_mode_sel0 : 1; + uint32_t power_mode_sel1 : 1; + uint32_t power_mode_sel2 : 1; + uint32_t power_mode_sel3 : 1; + uint32_t power_mode_sel4 : 1; + uint32_t power_mode_sel5 : 1; + uint32_t power_mode_sel6 : 1; + uint32_t power_mode_sel7 : 1; + uint32_t reserved : 24; +} __attribute__((packed, aligned(4))) sysctl_power_sel_t; + +/** + * @brief System controller object + * + * The System controller is a peripheral device mapped in the + * internal memory map, discoverable in the Configuration String. + * It is responsible for low-level configuration of all system + * related peripheral device. It contain PLL controller, clock + * controller, reset controller, DMA handshake controller, SPI + * controller, timer controller, WDT controller and sleep + * controller. + */ +typedef struct _sysctl +{ + /* No. 0 (0x00): Git short commit id */ + sysctl_git_id_t git_id; + /* No. 1 (0x04): System clock base frequency */ + sysctl_clk_freq_t clk_freq; + /* No. 2 (0x08): PLL0 controller */ + sysctl_pll0_t pll0; + /* No. 3 (0x0c): PLL1 controller */ + sysctl_pll1_t pll1; + /* No. 4 (0x10): PLL2 controller */ + sysctl_pll2_t pll2; + /* No. 5 (0x14): Reserved */ + uint32_t resv5; + /* No. 6 (0x18): PLL lock tester */ + sysctl_pll_lock_t pll_lock; + /* No. 7 (0x1c): AXI ROM detector */ + sysctl_rom_error_t rom_error; + /* No. 8 (0x20): Clock select controller0 */ + sysctl_clk_sel0_t clk_sel0; + /* No. 9 (0x24): Clock select controller1 */ + sysctl_clk_sel1_t clk_sel1; + /* No. 10 (0x28): Central clock enable */ + sysctl_clk_en_cent_t clk_en_cent; + /* No. 11 (0x2c): Peripheral clock enable */ + sysctl_clk_en_peri_t clk_en_peri; + /* No. 12 (0x30): Soft reset ctrl */ + sysctl_soft_reset_t soft_reset; + /* No. 13 (0x34): Peripheral reset controller */ + sysctl_peri_reset_t peri_reset; + /* No. 14 (0x38): Clock threshold controller 0 */ + sysctl_clk_th0_t clk_th0; + /* No. 15 (0x3c): Clock threshold controller 1 */ + sysctl_clk_th1_t clk_th1; + /* No. 16 (0x40): Clock threshold controller 2 */ + sysctl_clk_th2_t clk_th2; + /* No. 17 (0x44): Clock threshold controller 3 */ + sysctl_clk_th3_t clk_th3; + /* No. 18 (0x48): Clock threshold controller 4 */ + sysctl_clk_th4_t clk_th4; + /* No. 19 (0x4c): Clock threshold controller 5 */ + sysctl_clk_th5_t clk_th5; + /* No. 20 (0x50): Clock threshold controller 6 */ + sysctl_clk_th6_t clk_th6; + /* No. 21 (0x54): Miscellaneous controller */ + sysctl_misc_t misc; + /* No. 22 (0x58): Peripheral controller */ + sysctl_peri_t peri; + /* No. 23 (0x5c): SPI sleep controller */ + sysctl_spi_sleep_t spi_sleep; + /* No. 24 (0x60): Reset source status */ + sysctl_reset_status_t reset_status; + /* No. 25 (0x64): DMA handshake selector */ + sysctl_dma_sel0_t dma_sel0; + /* No. 26 (0x68): DMA handshake selector */ + sysctl_dma_sel1_t dma_sel1; + /* No. 27 (0x6c): IO Power Mode Select controller */ + sysctl_power_sel_t power_sel; + /* No. 28 (0x70): Reserved */ + uint32_t resv28; + /* No. 29 (0x74): Reserved */ + uint32_t resv29; + /* No. 30 (0x78): Reserved */ + uint32_t resv30; + /* No. 31 (0x7c): Reserved */ + uint32_t resv31; +} __attribute__((packed, aligned(4))) sysctl_t; + +/** + * @brief Abstruct PLL struct + */ +typedef struct _sysctl_general_pll +{ + uint32_t clkr : 4; + uint32_t clkf : 6; + uint32_t clkod : 4; + uint32_t bwadj : 6; + uint32_t pll_reset : 1; + uint32_t pll_pwrd : 1; + uint32_t pll_intfb : 1; + uint32_t pll_bypass : 1; + uint32_t pll_test : 1; + uint32_t pll_out_en : 1; + uint32_t pll_ckin_sel : 2; + uint32_t reserved : 4; +} __attribute__((packed, aligned(4))) sysctl_general_pll_t; + +/** + * @brief System controller object instanse + */ +extern volatile sysctl_t *const sysctl; + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_SYSCTL_H */ diff --git a/Kboot/src/bootloader_hi/main.c b/Kboot/src/bootloader_hi/main.c new file mode 100644 index 0000000..bd7478c --- /dev/null +++ b/Kboot/src/bootloader_hi/main.c @@ -0,0 +1,562 @@ +/* Copyright 2019 LoBo + * + * K210 Bootloader stage_1 + * ver. 1.4.1, 01/2020 + * + * 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. + */ + +/* + * ----------------------------------------------------------------------------- + * KBoot SPI Flash layout: + * ----------------------------------------------------------------------------- + * From To Length Comment + * ----------------------------------------------------------------------------- + * 0x00000000 0x00000FFF 4K bootloader stage_0 code + * 0x00001000 0x00003FFF 12K bootloader stage_1 code + * 0x00004000 0x00004FFF 4K boot configuration sector (256B used) + * 0x00005000 0x00005FFF 4K boot configuration sector BACKUP (256B used) + * 0x00006000 0x0000FFFF 40K reserved + * ----------------------------------------------------------------------------- + * 0x00010000 default application, optional, recommended + * flash_end user area, app code, file systems, data... + * ----------------------------------------------------------------------------- + */ + + +#include "spi.h" +#include "sysctl.h" +#include "fpioa.h" +#include "gpiohs.h" +#include "sha256.h" +#include "encoding.h" +#include "config.h" + +// Constants +/* + * Pin used to enter interactive mode and request the user + * to select which application to load + * Any valid and not used K210 gpio can be used except gpio#16 (0 ~ 15 & 17 ~ 47) + */ +//#define BOOT_PIN 18 +#define GPIO_KEY 2 + +#define DEFAULT_APP_ADDR 0x00010000 // default application flash address (64K) +#define APP_START_ADDR 0x80000000 // application start address in K210 SRAM +#define BOOT_CONFIG_ADDR 0x00004000 // main boot config sector in flash at 52K +#define BOOT_CONFIG_ITEMS 8 // number of handled config entries + +// boot config magic number (bits 4~31) +// flag: bit0 - active; bit1 - crc flag; bit2 - SHA flag; bit3 - check size +#define MAGIC_ID 0x5AA5D0C0 +#define MAGIC_ID_MASK 0xFFFFFFF0 +#define MAGIC_ID_FLAG 0xA55A60C0 +#define MAGIC_ID_FLAG_MASK 0xFFFFFFC0 +#define CFG_APP_FLAG_ACTIVE 0x00000001 +#define CFG_APP_FLAG_CRC32 0x00000002 +#define CFG_APP_FLAG_SHA256 0x00000004 +#define CFG_APP_FLAG_SIZE 0x00000008 + +// aplications limits +#define MIN_APP_FLASH_ADDR 0x00010000 // minimal application address in Flash: 64K +#define MAX_APP_FLASH_ADDR 0x00800000 // mmaximal application address in Flash: 8M +#define MIN_APP_FLASH_SIZE 0x00004000 // minimal application size in Flash: 16K +#define MAX_APP_FLASH_SIZE 0x00300000 // mmaximal application size in Flash: 3M + +// K210 ROM functions +typedef int rom_printf_func(const char * restrict format, ... ); +typedef int rom_getchar_func(); + +rom_printf_func *rom_printf = (rom_printf_func*)0x88001418; // fixed address in ROM +rom_printf_func *rom_printk = (rom_printf_func*)0x880016b0; // fixed address in ROM +rom_getchar_func *rom_getchar = (rom_getchar_func*)0x88008bd0; // fixed address in ROM + +// Variables + +#if FIRMWARE_SIZE +// variables used to provide mboot info to the loaded application +volatile uint32_t *ld_mbootid = (volatile uint32_t *)(APP_START_ADDR+FIRMWARE_SIZE); +volatile uint32_t *ld_address = (volatile uint32_t *)(APP_START_ADDR+FIRMWARE_SIZE+4); +volatile uint32_t *ld_size = (volatile uint32_t *)(APP_START_ADDR+FIRMWARE_SIZE+8); +#endif + +volatile sysctl_t *const sysctl = (volatile sysctl_t *)SYSCTL_BASE_ADDR; + +static uint32_t cfg_magic = 0; +static uint32_t cfg_address = 0; +static uint32_t cfg_size = 0; +static uint32_t cfg_crc = 0; +static uint8_t cfg_info[16] = "App name"; +static uint8_t available_apps[BOOT_CONFIG_ITEMS] = {0}; + +static uint64_t app_start = APP_START_ADDR; +static uint32_t app_flash_start = DEFAULT_APP_ADDR; +static uint32_t app_size = 0; +static uint8_t *app_flash_ptr = (uint8_t *)SPI3_BASE_ADDR; +static uint8_t *app_sram_ptr = (uint8_t *)APP_START_ADDR; + +static uint32_t *cfg_flash_ptr = (uint32_t *)(SPI3_BASE_ADDR+BOOT_CONFIG_ADDR); +static uint8_t *cfg_flash_bptr = (uint8_t *)(SPI3_BASE_ADDR+BOOT_CONFIG_ADDR); + +static uint32_t i = 0; +static uint32_t cfg_offset = 0; +static uint32_t offset = 0; +static uint8_t key = 0; +static uint32_t crc32; + +static uint8_t app_hash[SHA256_HASH_LEN] = {0}; +static uint8_t hash[SHA256_HASH_LEN] = {0}; +static uint8_t buffer[1024] = {0}; +static sha256_context_t context; + +static uint32_t boot_pin = 1; +static int char_in = 0; +static uint32_t print_enabled = 1; + +static uint32_t core0_sync = 0; +static uint32_t core1_sync = 0; + + +// Printing messages if interactive mode is enabled +// K210 ROM code is used for printing +#define LOG(format, ...) \ + do \ + { \ + if (print_enabled) { \ + rom_printk(format, ##__VA_ARGS__); \ + usleep(200); \ + } \ + } while(0) + + +// ==== Local functions === + +/* + * Get uint32_t value from Flash + * 8-bit Flash pionter is used, + * so the byte order must be swapped + */ +//----------------------------------------- +static uint32_t flash2uint32(uint32_t addr) +{ + uint32_t val = app_flash_ptr[addr]; + val += app_flash_ptr[addr+1] << 8; + val += app_flash_ptr[addr+2] << 16; + val += app_flash_ptr[addr+3] << 24; + return val; +} + +/* + * Get all configuration parameters + * for config sector entry at index 'i' + * into static variables + */ +//-------------------------------- +static void get_params(uint32_t i) +{ + offset = (i*8) + (cfg_offset / 4); // 32bit offset in current config sector + cfg_magic = cfg_flash_ptr[offset + 0]; + cfg_address = cfg_flash_ptr[offset + 1]; + cfg_size = cfg_flash_ptr[offset + 2]; + cfg_crc = cfg_flash_ptr[offset + 3]; + + // Get app description + offset = (i*32) + cfg_offset + 0x10; // 8bit offset in current config sector + key = cfg_flash_bptr[offset]; // dummy read needed to switch to 8bit XiP read + for (int n=0; n<16; n++) { + cfg_info[n] = cfg_flash_bptr[offset + n]; + } + cfg_info[15] = 0; +} + +/* + * Check the application's SHA256 hash + * The hash is 32 bytes long and written after the application's code + * by Kflash or other application + */ +//-------------------------- +static uint32_t app_sha256() +{ + int size = cfg_size+5; + int sz; + sha256_init(&context, size); + uint32_t idx = 0; + + while (size > 0) { + sz = (size >= 1024) ? 1024 : size; + for (int n=0; n> 1) ^ (0xEDB88320 & mask); + } + } + crc32 = ~crc; + if (crc32 != cfg_crc) { + LOG("CRC32 error, "); + return 0; + } + return 1; +} + +/* + * Check if the current application parameters + * points to the valid Kboot application + */ +//------------------------- +static uint32_t app_check() +{ + uint8_t key = app_flash_ptr[cfg_address]; // must be 0, SHA256 key NOT specified + uint32_t sz = flash2uint32(cfg_address+1); // app size + //uint32_t app_id = flash2uint32(cfg_address+7); // app ID = MAGIC_ID + + if (key != 0) return 0; + //if (app_id != MAGIC_ID) return 0; + if ((cfg_magic & CFG_APP_FLAG_SIZE) && (cfg_size != sz)) return 0; + else if (cfg_size != sz) { + LOG("app_size=%u, ", sz); + cfg_size = sz; + } + + if (cfg_magic & CFG_APP_FLAG_SHA256) { + // SHA256 check was requested, check flash data + return app_sha256(); + } + if (cfg_magic & CFG_APP_FLAG_CRC32) { + // CRC check was requested, check flash data + return app_crc32(); + } + return 1; +} + +/* + * After the 1st part of the kboot code is executed + * the execution is continued here. + * This is the first location containing the hi sram kboot code! + * ------------------------------------------------------------- + * We come here twice: running on core #0 and running on core #1 + * ------------------------------------------------------------- + */ + +//============ +int main(void) +{ + // Initialize bss data to 0, not needed as no bss data is used + /* + extern unsigned int _bss; + extern unsigned int _ebss; + unsigned int *dst; + dst = &_bss; + while(dst < &_ebss) + *dst++ = 0; + */ + + // Check the core we are running on + i = read_csr(mhartid); + //-------------------------------------------------------- + if (i != 0) { + // ============================ + // ==== Running on core #1 ==== + // ============================ + core0_sync = 1; + // wait for synchronization with core #0 + while (core1_sync == 0) { + asm("nop"); + } + + /* + * core #0 is done, the application code is transfered + * to sram at 0x80000000, continue the execution there + * + * each core has separate instruction cache + * we must clear it before continuing + */ + usleep(1000); + asm("fence"); // D-Cache; this may not be necessary, but it looks it doesn't hurt if it is executed + asm("fence.i"); // I-Cache + //asm("li a0, 1"); + asm ("jr %0" : : "r"(app_start)); + + // This should never be reached! + while (1) { + asm("nop"); + } + } + //-------------------------------------------------------- + + // ============================ + // ==== Running on core #0 ==== + // ============================ + + // wait for synchronization with core #1 + while (core0_sync == 0) { + asm("nop"); + } + + // === Printing and Flash XiP mode were initialized in stage_0 === + + // Check if interractive mode can be enabled + boot_pin = 1; + cfg_magic = cfg_flash_ptr[BOOT_CONFIG_ITEMS*8]; + print_enabled = (cfg_magic == MAGIC_ID) ? 0 : 1; + if (print_enabled) { + if ((cfg_magic & MAGIC_ID_FLAG_MASK) == MAGIC_ID_FLAG) { + // use provided pin number as boot pin + if ((cfg_magic & 0x3F) > 0) { + fpioa_set_function(cfg_magic & 0x3F, FUNC_GPIOHS2); + gpiohs_set_drive_mode(GPIO_KEY, GPIO_DM_INPUT_PULL_UP); + usleep(1000); + boot_pin = gpiohs_get_pin(GPIO_KEY); + } + } + else { + // use default pin number as boot pin + #if ((BOOT_PIN >= 0) && (BOOT_PIN < 48) && (BOOT_PIN != 16)) + fpioa_set_function(BOOT_PIN, FUNC_GPIOHS2); + gpiohs_set_drive_mode(GPIO_KEY, GPIO_DM_INPUT_PULL_UP); + usleep(1000); + boot_pin = gpiohs_get_pin(GPIO_KEY); + #endif + } + } + + LOG("\nK210 bootloader by LoBo v.1.4.3\n\n"); + + LOG("* Find applications in MAIN parameters\n"); + + // First we check the main config sector + app_flash_start = 0; + cfg_offset = 0; + + // === Read boot configuration from config sector === +check_cfg: + // Check all boot entries + for (i = 0; i < BOOT_CONFIG_ITEMS; i++) { + get_params(i); + + if ((cfg_magic & MAGIC_ID_MASK) == MAGIC_ID) { + // *** Valid configuration found + LOG(" %u: '%15s', ", i, cfg_info); + // Check if the Flash address is in range (512K ~ 8MB) + if ((cfg_address >= MIN_APP_FLASH_ADDR) && (cfg_address <= MAX_APP_FLASH_ADDR)) { + // Address valid, check if the size is in range (16K ~ 3MB) + if ((cfg_size >= MIN_APP_FLASH_SIZE) && (cfg_size <= MAX_APP_FLASH_SIZE)) { + // Valid size + LOG("@ 0x%08X, size=%u, ", cfg_address, cfg_size); + /* + * Basic check passed, now we can check the application's vilidity + * If in interractive mode, all applications are checked, + * otherwize, the application is checked only if flagged as active + */ + if ((cfg_magic & CFG_APP_FLAG_ACTIVE) || (boot_pin == 0)) { + // ** Check if valid application + if (app_check() == 0) { + LOG("App CHECK failed\n"); + continue; + } + LOG("App ok, "); + available_apps[i] = 1; + } + else { + LOG("not checked, "); + } + // ** Check if this is an active config (bit #0 set) + if ((cfg_magic & CFG_APP_FLAG_ACTIVE) == 0) { + LOG("NOT "); + } + else { + if (app_flash_start == 0) { + app_size = cfg_size; + app_flash_start = cfg_address; + } + if (boot_pin > 0) { + // Active application found and cheched and not in interractive mode + LOG("ACTIVE\n"); + break; + } + } + LOG("ACTIVE\n"); + } + else { + LOG("size Error!\n"); + } + } + else { + LOG("address Error!\n"); + } + } + } + + // check if any valid application was found + for (i = 0; i < BOOT_CONFIG_ITEMS; i++) { + if (available_apps[i]) break; + } + if ((app_flash_start == 0) && (i >= BOOT_CONFIG_ITEMS)) { + // No valid application found + if (cfg_offset == 0) { + // no valid entry found in main config sector, check the backup one + LOG("\n* Find applications in BACKUP parameters\n"); + cfg_offset = 4096; + //if (boot_pin == 0) { + // cfg_magic = cfg_flash_ptr[4096+BOOT_CONFIG_ITEMS]; + // boot_pin = (cfg_magic == MAGIC_ID) ? 1 : 0; + //} + goto check_cfg; + } + else { + LOG("\n* No app found, loading default\n"); + } + } + else if (boot_pin == 0) { + // === Interractive mode === + #if ((BOOT_PIN >= 0) && (BOOT_PIN < 48) && (BOOT_PIN != 16)) + // Check boot pin again + boot_pin = gpiohs_get_pin(GPIO_KEY); + #endif + if (boot_pin == 0) { + // ** request user to select the application to run + LOG("\nSelect the application number to load ["); + for (i = 0; i < BOOT_CONFIG_ITEMS; i++) { + if (available_apps[i]) { + LOG(" %u,", i); + } + } + LOG(" d=default ] ? "); + while (1) { + char_in = rom_getchar(); + if ((char_in == 'd') || (char_in == 'D')) { + // use default application + app_flash_start = DEFAULT_APP_ADDR; + break; + } + else { + char_in -= 0x30; + if ((char_in >= 0) && (char_in < BOOT_CONFIG_ITEMS)) { + if (available_apps[char_in]) { + get_params(char_in); + // get application's size and address in Flash + app_size = flash2uint32(cfg_address+1); + app_flash_start = cfg_address; + char_in += 0x30; + break; + } + } + char_in += 0x30; + LOG("%c? ", char_in); + } + } + LOG("%c\n\n", (char)char_in); + } + } + + #if FIRMWARE_SIZE + *ld_address = app_flash_start; + #endif + + // If default application is selected for load, get its size and check SHA hash + if (app_flash_start == 0) { + key = 1; + app_flash_start = DEFAULT_APP_ADDR; + app_size = flash2uint32(app_flash_start+1); // get app size + if ((app_size >= MIN_APP_FLASH_SIZE) && (app_size <= MAX_APP_FLASH_SIZE)) { + cfg_size = app_size; + cfg_address = app_flash_start; + // Check default application + if (app_sha256()) key = 0; + } + if (key) { + // Check failed + print_enabled = 1; + LOG("\n* Default application check failed!\n"); + LOG("* SYSTEM HALTED\n"); + while (1) { + asm ("nop"); + } + } + } + + // === Copy the application code from flash to SRAM === + #if FIRMWARE_SIZE + *ld_mbootid = MAGIC_ID; + *ld_size = app_size; + if (*ld_address == 0) { + *ld_address = app_flash_start | 0x80000000; + } + #endif + LOG("* Loading app from flash at 0x%08X (%u B)\n", app_flash_start, app_size); + + for (i=0; i < app_size; i++) { + app_sram_ptr[i] = app_flash_ptr[app_flash_start+i+5]; + } + + // === Start the application === + LOG("* Starting at 0x%08X ...\n\n", app_start); + usleep(1000); + + // Disable XIP mode + sysctl->peri.spi3_xip_en = 0; + + // === Jump to the loaded application start address === + /* + * each core has separate instruction cache + * we must clear it before continuing + */ + + core1_sync = 1; + asm("fence"); // D-Cache; this may not be necessary, but it looks it doesn't hurt if it is executed + asm("fence.i"); // I-Cache + asm ("jr %0" : : "r"(app_start)); + + // This should never be reached! + LOG("\nERROR, SYSTEM HALTED\n"); + while (1) { + asm ("nop"); + } + return 0; +} + diff --git a/Kboot/src/bootloader_hi/sha256.c b/Kboot/src/bootloader_hi/sha256.c new file mode 100644 index 0000000..1f3785b --- /dev/null +++ b/Kboot/src/bootloader_hi/sha256.c @@ -0,0 +1,136 @@ +/* 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 +#include "sha256.h" +#include "sysctl.h" +#include "encoding.h" + +#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) + +int usleep(uint64_t usec) +{ + uint64_t cycle = read_cycle(); + uint64_t nop_all = usec * DEFAULT_CPU_CLOCK / 1000000UL; + while(1) + { + if(read_cycle() - cycle >= nop_all) + break; + } + return 0; +} + + +volatile sha256_t *const sha256 = (volatile sha256_t *)SHA256_BASE_ADDR; +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, 0x00, 0x00}; + +static inline uint64_t byteswap64(uint64_t x) +{ + uint32_t a = (uint32_t)(x >> 32); + uint32_t b = (uint32_t)x; + return ((uint64_t)BYTESWAP(b) << 32) | (uint64_t)BYTESWAP(a); +} + +void sha256_init(sha256_context_t *context, size_t input_len) +{ + //sysctl_clock_enable(SYSCTL_CLOCK_SHA); + sysctl->clk_en_cent.apb0_clk_en = 1; + sysctl->clk_en_peri.sha_clk_en = 1; + //sysctl_reset(SYSCTL_RESET_SHA); + sysctl->peri_reset.sha_reset = 1; + usleep(10); + sysctl->peri_reset.sha_reset = 0; + + sha256->sha_num_reg.sha_data_cnt = (uint32_t)((input_len + SHA256_BLOCK_LEN + 8) / SHA256_BLOCK_LEN); + sha256->sha_function_reg_1.dma_en = 0x0; + sha256->sha_function_reg_0.sha_endian = SHA256_BIG_ENDIAN; + sha256->sha_function_reg_0.sha_en = ENABLE_SHA; + context->total_len = 0L; + context->buffer_len = 0L; +} + +void sha256_update(sha256_context_t *context, const void *input, size_t input_len) +{ + const uint8_t *data = input; + size_t buffer_bytes_left; + size_t bytes_to_copy; + uint32_t i; + + while(input_len) + { + buffer_bytes_left = SHA256_BLOCK_LEN - context->buffer_len; + bytes_to_copy = buffer_bytes_left; + if(bytes_to_copy > input_len) + bytes_to_copy = input_len; + memcpy(&context->buffer.bytes[context->buffer_len], data, bytes_to_copy); + context->total_len += bytes_to_copy * 8L; + context->buffer_len += bytes_to_copy; + data += bytes_to_copy; + input_len -= bytes_to_copy; + if(context->buffer_len == SHA256_BLOCK_LEN) + { + for(i = 0; i < 16; i++) + { + while(sha256->sha_function_reg_1.fifo_in_full) + ; + sha256->sha_data_in1 = context->buffer.words[i]; + } + context->buffer_len = 0L; + } + } +} + +void sha256_final(sha256_context_t *context, uint8_t *output) +{ + size_t bytes_to_pad; + size_t length_pad; + uint32_t i; + + bytes_to_pad = 120L - context->buffer_len; + if(bytes_to_pad > 64L) + bytes_to_pad -= 64L; + length_pad = BYTESWAP64(context->total_len); + sha256_update(context, padding, bytes_to_pad); + sha256_update(context, &length_pad, 8L); + while(!(sha256->sha_function_reg_0.sha_en)) + ; + if(output) + { + for(i = 0; i < SHA256_HASH_WORDS; i++) + { + *((uint32_t *)output) = sha256->sha_result[SHA256_HASH_WORDS - i - 1]; + output += 4; + } + } +} + +void sha256_hard_calculate(const uint8_t *input, size_t input_len, uint8_t *output) +{ + sha256_context_t sha; + sha256_init(&sha, input_len); + sha256_update(&sha, input, input_len); + sha256_final(&sha, output); +} diff --git a/Kboot/src/bootloader_lo/crt.S b/Kboot/src/bootloader_lo/crt.S new file mode 100644 index 0000000..a4a1df9 --- /dev/null +++ b/Kboot/src/bootloader_lo/crt.S @@ -0,0 +1,21 @@ +# Copyright 2019 LoBo (https://github.com/loboris) +# +# 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. + + +.section .text.start, "ax", @progbits +.globl _start +_start: +# Jump directly to 'main' + + j main diff --git a/Kboot/src/bootloader_lo/include/encoding.h b/Kboot/src/bootloader_lo/include/encoding.h new file mode 100644 index 0000000..3eebee5 --- /dev/null +++ b/Kboot/src/bootloader_lo/include/encoding.h @@ -0,0 +1,1325 @@ +/* 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 RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define MSTATUS_UIE 0x00000001U +#define MSTATUS_SIE 0x00000002U +#define MSTATUS_HIE 0x00000004U +#define MSTATUS_MIE 0x00000008U +#define MSTATUS_UPIE 0x00000010U +#define MSTATUS_SPIE 0x00000020U +#define MSTATUS_HPIE 0x00000040U +#define MSTATUS_MPIE 0x00000080U +#define MSTATUS_SPP 0x00000100U +#define MSTATUS_HPP 0x00000600U +#define MSTATUS_MPP 0x00001800U +#define MSTATUS_FS 0x00006000U +#define MSTATUS_XS 0x00018000U +#define MSTATUS_MPRV 0x00020000U +#define MSTATUS_PUM 0x00040000U +#define MSTATUS_MXR 0x00080000U +#define MSTATUS_VM 0x1F000000U +#define MSTATUS32_SD 0x80000000U +#define MSTATUS64_SD 0x8000000000000000U + +#define SSTATUS_UIE 0x00000001U +#define SSTATUS_SIE 0x00000002U +#define SSTATUS_UPIE 0x00000010U +#define SSTATUS_SPIE 0x00000020U +#define SSTATUS_SPP 0x00000100U +#define SSTATUS_FS 0x00006000U +#define SSTATUS_XS 0x00018000U +#define SSTATUS_PUM 0x00040000U +#define SSTATUS32_SD 0x80000000U +#define SSTATUS64_SD 0x8000000000000000U + +#define DCSR_XDEBUGVER (3U << 30) +#define DCSR_NDRESET (1U << 29) +#define DCSR_FULLRESET (1U << 28) +#define DCSR_EBREAKM (1U << 15) +#define DCSR_EBREAKH (1U << 14) +#define DCSR_EBREAKS (1U << 13) +#define DCSR_EBREAKU (1U << 12) +#define DCSR_STOPCYCLE (1U << 10) +#define DCSR_STOPTIME (1U << 9) +#define DCSR_CAUSE (7U << 6) +#define DCSR_DEBUGINT (1U << 5) +#define DCSR_HALT (1U << 3) +#define DCSR_STEP (1U << 2) +#define DCSR_PRV (3U << 0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_SELECT (1U << 19) +#define MCONTROL_TIMING (1U << 18) +#define MCONTROL_ACTION (0x3fU << 12) +#define MCONTROL_CHAIN (1U << 11) +#define MCONTROL_MATCH (0xfU << 7) +#define MCONTROL_M (1U << 6) +#define MCONTROL_H (1U << 5) +#define MCONTROL_S (1U << 4) +#define MCONTROL_U (1U << 3) +#define MCONTROL_EXECUTE (1U << 2) +#define MCONTROL_STORE (1U << 1) +#define MCONTROL_LOAD (1U << 0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1U << IRQ_S_SOFT) +#define MIP_HSIP (1U << IRQ_H_SOFT) +#define MIP_MSIP (1U << IRQ_M_SOFT) +#define MIP_STIP (1U << IRQ_S_TIMER) +#define MIP_HTIP (1U << IRQ_H_TIMER) +#define MIP_MTIP (1U << IRQ_M_TIMER) +#define MIP_SEIP (1U << IRQ_S_EXT) +#define MIP_HEIP (1U << IRQ_H_EXT) +#define MIP_MEIP (1U << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define VM_MBARE 0 +#define VM_MBB 1 +#define VM_MBBID 2 +#define VM_SV32 8 +#define VM_SV39 9 +#define VM_SV48 10 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000U +#define DEFAULT_NMIVEC 0x00001004U +#define DEFAULT_MTVEC 0x00001010U +#define CONFIG_STRING_ADDR 0x0000100CU +#define EXT_IO_BASE 0x40000000U +#define DRAM_BASE 0x80000000U + +/* page table entry (PTE) fields */ +#define PTE_V 0x001U /* Valid */ +#define PTE_R 0x002U /* Read */ +#define PTE_W 0x004U /* Write */ +#define PTE_X 0x008U /* Execute */ +#define PTE_U 0x010U /* User */ +#define PTE_G 0x020U /* Global */ +#define PTE_A 0x040U /* Accessed */ +#define PTE_D 0x080U /* Dirty */ +#define PTE_SOFT 0x300U /* Reserved for Software */ + +#define PTE_PPN_SHIFT 10 + +#define MCONTROL_TYPE(xlen) (0xfULL << ((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL << ((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL << ((xlen)-11)) + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#if defined(__riscv) + +#if defined(__riscv64) +#define MSTATUS_SD MSTATUS64_SD +#define SSTATUS_SD SSTATUS64_SD +#define RISCV_PGLEVEL_BITS 9 +#else +#define MSTATUS_SD MSTATUS32_SD +#define SSTATUS_SD SSTATUS32_SD +#define RISCV_PGLEVEL_BITS 10 +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#if defined(__GNUC__) + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ + else \ + asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \ + else \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define read_time() read_csr(mtime) +#define read_cycle() read_csr(mcycle) +#define current_coreid() read_csr(mhartid) + +#endif + +#endif + +#endif + +#endif + +#ifndef RISCV_ENCODING_H +#define RISCV_ENCODING_H +#define MATCH_BEQ 0x63U +#define MASK_BEQ 0x707fU +#define MATCH_BNE 0x1063U +#define MASK_BNE 0x707fU +#define MATCH_BLT 0x4063U +#define MASK_BLT 0x707fU +#define MATCH_BGE 0x5063U +#define MASK_BGE 0x707fU +#define MATCH_BLTU 0x6063U +#define MASK_BLTU 0x707fU +#define MATCH_BGEU 0x7063U +#define MASK_BGEU 0x707fU +#define MATCH_JALR 0x67U +#define MASK_JALR 0x707fU +#define MATCH_JAL 0x6fU +#define MASK_JAL 0x7fU +#define MATCH_LUI 0x37U +#define MASK_LUI 0x7fU +#define MATCH_AUIPC 0x17U +#define MASK_AUIPC 0x7fU +#define MATCH_ADDI 0x13U +#define MASK_ADDI 0x707fU +#define MATCH_SLLI 0x1013U +#define MASK_SLLI 0xfc00707fU +#define MATCH_SLTI 0x2013U +#define MASK_SLTI 0x707fU +#define MATCH_SLTIU 0x3013U +#define MASK_SLTIU 0x707fU +#define MATCH_XORI 0x4013U +#define MASK_XORI 0x707fU +#define MATCH_SRLI 0x5013U +#define MASK_SRLI 0xfc00707fU +#define MATCH_SRAI 0x40005013U +#define MASK_SRAI 0xfc00707fU +#define MATCH_ORI 0x6013U +#define MASK_ORI 0x707fU +#define MATCH_ANDI 0x7013U +#define MASK_ANDI 0x707fU +#define MATCH_ADD 0x33U +#define MASK_ADD 0xfe00707fU +#define MATCH_SUB 0x40000033U +#define MASK_SUB 0xfe00707fU +#define MATCH_SLL 0x1033U +#define MASK_SLL 0xfe00707fU +#define MATCH_SLT 0x2033U +#define MASK_SLT 0xfe00707fU +#define MATCH_SLTU 0x3033U +#define MASK_SLTU 0xfe00707fU +#define MATCH_XOR 0x4033U +#define MASK_XOR 0xfe00707fU +#define MATCH_SRL 0x5033U +#define MASK_SRL 0xfe00707fU +#define MATCH_SRA 0x40005033U +#define MASK_SRA 0xfe00707fU +#define MATCH_OR 0x6033U +#define MASK_OR 0xfe00707fU +#define MATCH_AND 0x7033U +#define MASK_AND 0xfe00707fU +#define MATCH_ADDIW 0x1bU +#define MASK_ADDIW 0x707fU +#define MATCH_SLLIW 0x101bU +#define MASK_SLLIW 0xfe00707fU +#define MATCH_SRLIW 0x501bU +#define MASK_SRLIW 0xfe00707fU +#define MATCH_SRAIW 0x4000501bU +#define MASK_SRAIW 0xfe00707fU +#define MATCH_ADDW 0x3bU +#define MASK_ADDW 0xfe00707fU +#define MATCH_SUBW 0x4000003bU +#define MASK_SUBW 0xfe00707fU +#define MATCH_SLLW 0x103bU +#define MASK_SLLW 0xfe00707fU +#define MATCH_SRLW 0x503bU +#define MASK_SRLW 0xfe00707fU +#define MATCH_SRAW 0x4000503bU +#define MASK_SRAW 0xfe00707fU +#define MATCH_LB 0x3U +#define MASK_LB 0x707fU +#define MATCH_LH 0x1003U +#define MASK_LH 0x707fU +#define MATCH_LW 0x2003U +#define MASK_LW 0x707fU +#define MATCH_LD 0x3003U +#define MASK_LD 0x707fU +#define MATCH_LBU 0x4003U +#define MASK_LBU 0x707fU +#define MATCH_LHU 0x5003U +#define MASK_LHU 0x707fU +#define MATCH_LWU 0x6003U +#define MASK_LWU 0x707fU +#define MATCH_SB 0x23U +#define MASK_SB 0x707fU +#define MATCH_SH 0x1023U +#define MASK_SH 0x707fU +#define MATCH_SW 0x2023U +#define MASK_SW 0x707fU +#define MATCH_SD 0x3023U +#define MASK_SD 0x707fU +#define MATCH_FENCE 0xfU +#define MASK_FENCE 0x707fU +#define MATCH_FENCE_I 0x100fU +#define MASK_FENCE_I 0x707fU +#define MATCH_MUL 0x2000033U +#define MASK_MUL 0xfe00707fU +#define MATCH_MULH 0x2001033U +#define MASK_MULH 0xfe00707fU +#define MATCH_MULHSU 0x2002033U +#define MASK_MULHSU 0xfe00707fU +#define MATCH_MULHU 0x2003033U +#define MASK_MULHU 0xfe00707fU +#define MATCH_DIV 0x2004033U +#define MASK_DIV 0xfe00707fU +#define MATCH_DIVU 0x2005033U +#define MASK_DIVU 0xfe00707fU +#define MATCH_REM 0x2006033U +#define MASK_REM 0xfe00707fU +#define MATCH_REMU 0x2007033U +#define MASK_REMU 0xfe00707fU +#define MATCH_MULW 0x200003bU +#define MASK_MULW 0xfe00707fU +#define MATCH_DIVW 0x200403bU +#define MASK_DIVW 0xfe00707fU +#define MATCH_DIVUW 0x200503bU +#define MASK_DIVUW 0xfe00707fU +#define MATCH_REMW 0x200603bU +#define MASK_REMW 0xfe00707fU +#define MATCH_REMUW 0x200703bU +#define MASK_REMUW 0xfe00707fU +#define MATCH_AMOADD_W 0x202fU +#define MASK_AMOADD_W 0xf800707fU +#define MATCH_AMOXOR_W 0x2000202fU +#define MASK_AMOXOR_W 0xf800707fU +#define MATCH_AMOOR_W 0x4000202fU +#define MASK_AMOOR_W 0xf800707fU +#define MATCH_AMOAND_W 0x6000202fU +#define MASK_AMOAND_W 0xf800707fU +#define MATCH_AMOMIN_W 0x8000202fU +#define MASK_AMOMIN_W 0xf800707fU +#define MATCH_AMOMAX_W 0xa000202fU +#define MASK_AMOMAX_W 0xf800707fU +#define MATCH_AMOMINU_W 0xc000202fU +#define MASK_AMOMINU_W 0xf800707fU +#define MATCH_AMOMAXU_W 0xe000202fU +#define MASK_AMOMAXU_W 0xf800707fU +#define MATCH_AMOSWAP_W 0x800202fU +#define MASK_AMOSWAP_W 0xf800707fU +#define MATCH_LR_W 0x1000202fU +#define MASK_LR_W 0xf9f0707fU +#define MATCH_SC_W 0x1800202fU +#define MASK_SC_W 0xf800707fU +#define MATCH_AMOADD_D 0x302fU +#define MASK_AMOADD_D 0xf800707fU +#define MATCH_AMOXOR_D 0x2000302fU +#define MASK_AMOXOR_D 0xf800707fU +#define MATCH_AMOOR_D 0x4000302fU +#define MASK_AMOOR_D 0xf800707fU +#define MATCH_AMOAND_D 0x6000302fU +#define MASK_AMOAND_D 0xf800707fU +#define MATCH_AMOMIN_D 0x8000302fU +#define MASK_AMOMIN_D 0xf800707fU +#define MATCH_AMOMAX_D 0xa000302fU +#define MASK_AMOMAX_D 0xf800707fU +#define MATCH_AMOMINU_D 0xc000302fU +#define MASK_AMOMINU_D 0xf800707fU +#define MATCH_AMOMAXU_D 0xe000302fU +#define MASK_AMOMAXU_D 0xf800707fU +#define MATCH_AMOSWAP_D 0x800302fU +#define MASK_AMOSWAP_D 0xf800707fU +#define MATCH_LR_D 0x1000302fU +#define MASK_LR_D 0xf9f0707fU +#define MATCH_SC_D 0x1800302fU +#define MASK_SC_D 0xf800707fU +#define MATCH_ECALL 0x73U +#define MASK_ECALL 0xffffffffU +#define MATCH_EBREAK 0x100073U +#define MASK_EBREAK 0xffffffffU +#define MATCH_URET 0x200073U +#define MASK_URET 0xffffffffU +#define MATCH_SRET 0x10200073U +#define MASK_SRET 0xffffffffU +#define MATCH_HRET 0x20200073U +#define MASK_HRET 0xffffffffU +#define MATCH_MRET 0x30200073U +#define MASK_MRET 0xffffffffU +#define MATCH_DRET 0x7b200073U +#define MASK_DRET 0xffffffffU +#define MATCH_SFENCE_VM 0x10400073U +#define MASK_SFENCE_VM 0xfff07fffU +#define MATCH_WFI 0x10500073U +#define MASK_WFI 0xffffffffU +#define MATCH_CSRRW 0x1073U +#define MASK_CSRRW 0x707fU +#define MATCH_CSRRS 0x2073U +#define MASK_CSRRS 0x707fU +#define MATCH_CSRRC 0x3073U +#define MASK_CSRRC 0x707fU +#define MATCH_CSRRWI 0x5073U +#define MASK_CSRRWI 0x707fU +#define MATCH_CSRRSI 0x6073U +#define MASK_CSRRSI 0x707fU +#define MATCH_CSRRCI 0x7073U +#define MASK_CSRRCI 0x707fU +#define MATCH_FADD_S 0x53U +#define MASK_FADD_S 0xfe00007fU +#define MATCH_FSUB_S 0x8000053U +#define MASK_FSUB_S 0xfe00007fU +#define MATCH_FMUL_S 0x10000053U +#define MASK_FMUL_S 0xfe00007fU +#define MATCH_FDIV_S 0x18000053U +#define MASK_FDIV_S 0xfe00007fU +#define MATCH_FSGNJ_S 0x20000053U +#define MASK_FSGNJ_S 0xfe00707fU +#define MATCH_FSGNJN_S 0x20001053U +#define MASK_FSGNJN_S 0xfe00707fU +#define MATCH_FSGNJX_S 0x20002053U +#define MASK_FSGNJX_S 0xfe00707fU +#define MATCH_FMIN_S 0x28000053U +#define MASK_FMIN_S 0xfe00707fU +#define MATCH_FMAX_S 0x28001053U +#define MASK_FMAX_S 0xfe00707fU +#define MATCH_FSQRT_S 0x58000053U +#define MASK_FSQRT_S 0xfff0007fU +#define MATCH_FADD_D 0x2000053U +#define MASK_FADD_D 0xfe00007fU +#define MATCH_FSUB_D 0xa000053U +#define MASK_FSUB_D 0xfe00007fU +#define MATCH_FMUL_D 0x12000053U +#define MASK_FMUL_D 0xfe00007fU +#define MATCH_FDIV_D 0x1a000053U +#define MASK_FDIV_D 0xfe00007fU +#define MATCH_FSGNJ_D 0x22000053U +#define MASK_FSGNJ_D 0xfe00707fU +#define MATCH_FSGNJN_D 0x22001053U +#define MASK_FSGNJN_D 0xfe00707fU +#define MATCH_FSGNJX_D 0x22002053U +#define MASK_FSGNJX_D 0xfe00707fU +#define MATCH_FMIN_D 0x2a000053U +#define MASK_FMIN_D 0xfe00707fU +#define MATCH_FMAX_D 0x2a001053U +#define MASK_FMAX_D 0xfe00707fU +#define MATCH_FCVT_S_D 0x40100053U +#define MASK_FCVT_S_D 0xfff0007fU +#define MATCH_FCVT_D_S 0x42000053U +#define MASK_FCVT_D_S 0xfff0007fU +#define MATCH_FSQRT_D 0x5a000053U +#define MASK_FSQRT_D 0xfff0007fU +#define MATCH_FLE_S 0xa0000053U +#define MASK_FLE_S 0xfe00707fU +#define MATCH_FLT_S 0xa0001053U +#define MASK_FLT_S 0xfe00707fU +#define MATCH_FEQ_S 0xa0002053U +#define MASK_FEQ_S 0xfe00707fU +#define MATCH_FLE_D 0xa2000053U +#define MASK_FLE_D 0xfe00707fU +#define MATCH_FLT_D 0xa2001053U +#define MASK_FLT_D 0xfe00707fU +#define MATCH_FEQ_D 0xa2002053U +#define MASK_FEQ_D 0xfe00707fU +#define MATCH_FCVT_W_S 0xc0000053U +#define MASK_FCVT_W_S 0xfff0007fU +#define MATCH_FCVT_WU_S 0xc0100053U +#define MASK_FCVT_WU_S 0xfff0007fU +#define MATCH_FCVT_L_S 0xc0200053U +#define MASK_FCVT_L_S 0xfff0007fU +#define MATCH_FCVT_LU_S 0xc0300053U +#define MASK_FCVT_LU_S 0xfff0007fU +#define MATCH_FMV_X_S 0xe0000053U +#define MASK_FMV_X_S 0xfff0707fU +#define MATCH_FCLASS_S 0xe0001053U +#define MASK_FCLASS_S 0xfff0707fU +#define MATCH_FCVT_W_D 0xc2000053U +#define MASK_FCVT_W_D 0xfff0007fU +#define MATCH_FCVT_WU_D 0xc2100053U +#define MASK_FCVT_WU_D 0xfff0007fU +#define MATCH_FCVT_L_D 0xc2200053U +#define MASK_FCVT_L_D 0xfff0007fU +#define MATCH_FCVT_LU_D 0xc2300053U +#define MASK_FCVT_LU_D 0xfff0007fU +#define MATCH_FMV_X_D 0xe2000053U +#define MASK_FMV_X_D 0xfff0707fU +#define MATCH_FCLASS_D 0xe2001053U +#define MASK_FCLASS_D 0xfff0707fU +#define MATCH_FCVT_S_W 0xd0000053U +#define MASK_FCVT_S_W 0xfff0007fU +#define MATCH_FCVT_S_WU 0xd0100053U +#define MASK_FCVT_S_WU 0xfff0007fU +#define MATCH_FCVT_S_L 0xd0200053U +#define MASK_FCVT_S_L 0xfff0007fU +#define MATCH_FCVT_S_LU 0xd0300053U +#define MASK_FCVT_S_LU 0xfff0007fU +#define MATCH_FMV_S_X 0xf0000053U +#define MASK_FMV_S_X 0xfff0707fU +#define MATCH_FCVT_D_W 0xd2000053U +#define MASK_FCVT_D_W 0xfff0007fU +#define MATCH_FCVT_D_WU 0xd2100053U +#define MASK_FCVT_D_WU 0xfff0007fU +#define MATCH_FCVT_D_L 0xd2200053U +#define MASK_FCVT_D_L 0xfff0007fU +#define MATCH_FCVT_D_LU 0xd2300053U +#define MASK_FCVT_D_LU 0xfff0007fU +#define MATCH_FMV_D_X 0xf2000053U +#define MASK_FMV_D_X 0xfff0707fU +#define MATCH_FLW 0x2007U +#define MASK_FLW 0x707fU +#define MATCH_FLD 0x3007U +#define MASK_FLD 0x707fU +#define MATCH_FSW 0x2027U +#define MASK_FSW 0x707fU +#define MATCH_FSD 0x3027U +#define MASK_FSD 0x707fU +#define MATCH_FMADD_S 0x43U +#define MASK_FMADD_S 0x600007fU +#define MATCH_FMSUB_S 0x47U +#define MASK_FMSUB_S 0x600007fU +#define MATCH_FNMSUB_S 0x4bU +#define MASK_FNMSUB_S 0x600007fU +#define MATCH_FNMADD_S 0x4fU +#define MASK_FNMADD_S 0x600007fU +#define MATCH_FMADD_D 0x2000043U +#define MASK_FMADD_D 0x600007fU +#define MATCH_FMSUB_D 0x2000047U +#define MASK_FMSUB_D 0x600007fU +#define MATCH_FNMSUB_D 0x200004bU +#define MASK_FNMSUB_D 0x600007fU +#define MATCH_FNMADD_D 0x200004fU +#define MASK_FNMADD_D 0x600007fU +#define MATCH_C_NOP 0x1U +#define MASK_C_NOP 0xffffU +#define MATCH_C_ADDI16SP 0x6101U +#define MASK_C_ADDI16SP 0xef83U +#define MATCH_C_JR 0x8002U +#define MASK_C_JR 0xf07fU +#define MATCH_C_JALR 0x9002U +#define MASK_C_JALR 0xf07fU +#define MATCH_C_EBREAK 0x9002U +#define MASK_C_EBREAK 0xffffU +#define MATCH_C_LD 0x6000U +#define MASK_C_LD 0xe003U +#define MATCH_C_SD 0xe000U +#define MASK_C_SD 0xe003U +#define MATCH_C_ADDIW 0x2001U +#define MASK_C_ADDIW 0xe003U +#define MATCH_C_LDSP 0x6002U +#define MASK_C_LDSP 0xe003U +#define MATCH_C_SDSP 0xe002U +#define MASK_C_SDSP 0xe003U +#define MATCH_C_ADDI4SPN 0x0U +#define MASK_C_ADDI4SPN 0xe003U +#define MATCH_C_FLD 0x2000U +#define MASK_C_FLD 0xe003U +#define MATCH_C_LW 0x4000U +#define MASK_C_LW 0xe003U +#define MATCH_C_FLW 0x6000U +#define MASK_C_FLW 0xe003U +#define MATCH_C_FSD 0xa000U +#define MASK_C_FSD 0xe003U +#define MATCH_C_SW 0xc000U +#define MASK_C_SW 0xe003U +#define MATCH_C_FSW 0xe000U +#define MASK_C_FSW 0xe003U +#define MATCH_C_ADDI 0x1U +#define MASK_C_ADDI 0xe003U +#define MATCH_C_JAL 0x2001U +#define MASK_C_JAL 0xe003U +#define MATCH_C_LI 0x4001U +#define MASK_C_LI 0xe003U +#define MATCH_C_LUI 0x6001U +#define MASK_C_LUI 0xe003U +#define MATCH_C_SRLI 0x8001U +#define MASK_C_SRLI 0xec03U +#define MATCH_C_SRAI 0x8401U +#define MASK_C_SRAI 0xec03U +#define MATCH_C_ANDI 0x8801U +#define MASK_C_ANDI 0xec03U +#define MATCH_C_SUB 0x8c01U +#define MASK_C_SUB 0xfc63U +#define MATCH_C_XOR 0x8c21U +#define MASK_C_XOR 0xfc63U +#define MATCH_C_OR 0x8c41U +#define MASK_C_OR 0xfc63U +#define MATCH_C_AND 0x8c61U +#define MASK_C_AND 0xfc63U +#define MATCH_C_SUBW 0x9c01U +#define MASK_C_SUBW 0xfc63U +#define MATCH_C_ADDW 0x9c21U +#define MASK_C_ADDW 0xfc63U +#define MATCH_C_J 0xa001U +#define MASK_C_J 0xe003U +#define MATCH_C_BEQZ 0xc001U +#define MASK_C_BEQZ 0xe003U +#define MATCH_C_BNEZ 0xe001U +#define MASK_C_BNEZ 0xe003U +#define MATCH_C_SLLI 0x2U +#define MASK_C_SLLI 0xe003U +#define MATCH_C_FLDSP 0x2002U +#define MASK_C_FLDSP 0xe003U +#define MATCH_C_LWSP 0x4002U +#define MASK_C_LWSP 0xe003U +#define MATCH_C_FLWSP 0x6002U +#define MASK_C_FLWSP 0xe003U +#define MATCH_C_MV 0x8002U +#define MASK_C_MV 0xf003U +#define MATCH_C_ADD 0x9002U +#define MASK_C_ADD 0xf003U +#define MATCH_C_FSDSP 0xa002U +#define MASK_C_FSDSP 0xe003U +#define MATCH_C_SWSP 0xc002U +#define MASK_C_SWSP 0xe003U +#define MATCH_C_FSWSP 0xe002U +#define MASK_C_FSWSP 0xe003U +#define MATCH_CUSTOM0 0xbU +#define MASK_CUSTOM0 0x707fU +#define MATCH_CUSTOM0_RS1 0x200bU +#define MASK_CUSTOM0_RS1 0x707fU +#define MATCH_CUSTOM0_RS1_RS2 0x300bU +#define MASK_CUSTOM0_RS1_RS2 0x707fU +#define MATCH_CUSTOM0_RD 0x400bU +#define MASK_CUSTOM0_RD 0x707fU +#define MATCH_CUSTOM0_RD_RS1 0x600bU +#define MASK_CUSTOM0_RD_RS1 0x707fU +#define MATCH_CUSTOM0_RD_RS1_RS2 0x700bU +#define MASK_CUSTOM0_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM1 0x2bU +#define MASK_CUSTOM1 0x707fU +#define MATCH_CUSTOM1_RS1 0x202bU +#define MASK_CUSTOM1_RS1 0x707fU +#define MATCH_CUSTOM1_RS1_RS2 0x302bU +#define MASK_CUSTOM1_RS1_RS2 0x707fU +#define MATCH_CUSTOM1_RD 0x402bU +#define MASK_CUSTOM1_RD 0x707fU +#define MATCH_CUSTOM1_RD_RS1 0x602bU +#define MASK_CUSTOM1_RD_RS1 0x707fU +#define MATCH_CUSTOM1_RD_RS1_RS2 0x702bU +#define MASK_CUSTOM1_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM2 0x5bU +#define MASK_CUSTOM2 0x707fU +#define MATCH_CUSTOM2_RS1 0x205bU +#define MASK_CUSTOM2_RS1 0x707fU +#define MATCH_CUSTOM2_RS1_RS2 0x305bU +#define MASK_CUSTOM2_RS1_RS2 0x707fU +#define MATCH_CUSTOM2_RD 0x405bU +#define MASK_CUSTOM2_RD 0x707fU +#define MATCH_CUSTOM2_RD_RS1 0x605bU +#define MASK_CUSTOM2_RD_RS1 0x707fU +#define MATCH_CUSTOM2_RD_RS1_RS2 0x705bU +#define MASK_CUSTOM2_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM3 0x7bU +#define MASK_CUSTOM3 0x707fU +#define MATCH_CUSTOM3_RS1 0x207bU +#define MASK_CUSTOM3_RS1 0x707fU +#define MATCH_CUSTOM3_RS1_RS2 0x307bU +#define MASK_CUSTOM3_RS1_RS2 0x707fU +#define MATCH_CUSTOM3_RD 0x407bU +#define MASK_CUSTOM3_RD 0x707fU +#define MATCH_CUSTOM3_RD_RS1 0x607bU +#define MASK_CUSTOM3_RD_RS1 0x707fU +#define MATCH_CUSTOM3_RD_RS1_RS2 0x707bU +#define MASK_CUSTOM3_RD_RS1_RS2 0x707fU +#define CSR_FFLAGS 0x1U +#define CSR_FRM 0x2U +#define CSR_FCSR 0x3U +#define CSR_CYCLE 0xc00U +#define CSR_TIME 0xc01U +#define CSR_INSTRET 0xc02U +#define CSR_HPMCOUNTER3 0xc03U +#define CSR_HPMCOUNTER4 0xc04U +#define CSR_HPMCOUNTER5 0xc05U +#define CSR_HPMCOUNTER6 0xc06U +#define CSR_HPMCOUNTER7 0xc07U +#define CSR_HPMCOUNTER8 0xc08U +#define CSR_HPMCOUNTER9 0xc09U +#define CSR_HPMCOUNTER10 0xc0aU +#define CSR_HPMCOUNTER11 0xc0bU +#define CSR_HPMCOUNTER12 0xc0cU +#define CSR_HPMCOUNTER13 0xc0dU +#define CSR_HPMCOUNTER14 0xc0eU +#define CSR_HPMCOUNTER15 0xc0fU +#define CSR_HPMCOUNTER16 0xc10U +#define CSR_HPMCOUNTER17 0xc11U +#define CSR_HPMCOUNTER18 0xc12U +#define CSR_HPMCOUNTER19 0xc13U +#define CSR_HPMCOUNTER20 0xc14U +#define CSR_HPMCOUNTER21 0xc15U +#define CSR_HPMCOUNTER22 0xc16U +#define CSR_HPMCOUNTER23 0xc17U +#define CSR_HPMCOUNTER24 0xc18U +#define CSR_HPMCOUNTER25 0xc19U +#define CSR_HPMCOUNTER26 0xc1aU +#define CSR_HPMCOUNTER27 0xc1bU +#define CSR_HPMCOUNTER28 0xc1cU +#define CSR_HPMCOUNTER29 0xc1dU +#define CSR_HPMCOUNTER30 0xc1eU +#define CSR_HPMCOUNTER31 0xc1fU +#define CSR_SSTATUS 0x100U +#define CSR_SIE 0x104U +#define CSR_STVEC 0x105U +#define CSR_SSCRATCH 0x140U +#define CSR_SEPC 0x141U +#define CSR_SCAUSE 0x142U +#define CSR_SBADADDR 0x143U +#define CSR_SIP 0x144U +#define CSR_SPTBR 0x180U +#define CSR_MSTATUS 0x300U +#define CSR_MISA 0x301U +#define CSR_MEDELEG 0x302U +#define CSR_MIDELEG 0x303U +#define CSR_MIE 0x304U +#define CSR_MTVEC 0x305U +#define CSR_MSCRATCH 0x340U +#define CSR_MEPC 0x341U +#define CSR_MCAUSE 0x342U +#define CSR_MBADADDR 0x343U +#define CSR_MIP 0x344U +#define CSR_TSELECT 0x7a0U +#define CSR_TDATA1 0x7a1U +#define CSR_TDATA2 0x7a2U +#define CSR_TDATA3 0x7a3U +#define CSR_DCSR 0x7b0U +#define CSR_DPC 0x7b1U +#define CSR_DSCRATCH 0x7b2U +#define CSR_MCYCLE 0xb00U +#define CSR_MINSTRET 0xb02U +#define CSR_MHPMCOUNTER3 0xb03U +#define CSR_MHPMCOUNTER4 0xb04U +#define CSR_MHPMCOUNTER5 0xb05U +#define CSR_MHPMCOUNTER6 0xb06U +#define CSR_MHPMCOUNTER7 0xb07U +#define CSR_MHPMCOUNTER8 0xb08U +#define CSR_MHPMCOUNTER9 0xb09U +#define CSR_MHPMCOUNTER10 0xb0aU +#define CSR_MHPMCOUNTER11 0xb0bU +#define CSR_MHPMCOUNTER12 0xb0cU +#define CSR_MHPMCOUNTER13 0xb0dU +#define CSR_MHPMCOUNTER14 0xb0eU +#define CSR_MHPMCOUNTER15 0xb0fU +#define CSR_MHPMCOUNTER16 0xb10U +#define CSR_MHPMCOUNTER17 0xb11U +#define CSR_MHPMCOUNTER18 0xb12U +#define CSR_MHPMCOUNTER19 0xb13U +#define CSR_MHPMCOUNTER20 0xb14U +#define CSR_MHPMCOUNTER21 0xb15U +#define CSR_MHPMCOUNTER22 0xb16U +#define CSR_MHPMCOUNTER23 0xb17U +#define CSR_MHPMCOUNTER24 0xb18U +#define CSR_MHPMCOUNTER25 0xb19U +#define CSR_MHPMCOUNTER26 0xb1aU +#define CSR_MHPMCOUNTER27 0xb1bU +#define CSR_MHPMCOUNTER28 0xb1cU +#define CSR_MHPMCOUNTER29 0xb1dU +#define CSR_MHPMCOUNTER30 0xb1eU +#define CSR_MHPMCOUNTER31 0xb1fU +#define CSR_MUCOUNTEREN 0x320U +#define CSR_MSCOUNTEREN 0x321U +#define CSR_MHPMEVENT3 0x323U +#define CSR_MHPMEVENT4 0x324U +#define CSR_MHPMEVENT5 0x325U +#define CSR_MHPMEVENT6 0x326U +#define CSR_MHPMEVENT7 0x327U +#define CSR_MHPMEVENT8 0x328U +#define CSR_MHPMEVENT9 0x329U +#define CSR_MHPMEVENT10 0x32aU +#define CSR_MHPMEVENT11 0x32bU +#define CSR_MHPMEVENT12 0x32cU +#define CSR_MHPMEVENT13 0x32dU +#define CSR_MHPMEVENT14 0x32eU +#define CSR_MHPMEVENT15 0x32fU +#define CSR_MHPMEVENT16 0x330U +#define CSR_MHPMEVENT17 0x331U +#define CSR_MHPMEVENT18 0x332U +#define CSR_MHPMEVENT19 0x333U +#define CSR_MHPMEVENT20 0x334U +#define CSR_MHPMEVENT21 0x335U +#define CSR_MHPMEVENT22 0x336U +#define CSR_MHPMEVENT23 0x337U +#define CSR_MHPMEVENT24 0x338U +#define CSR_MHPMEVENT25 0x339U +#define CSR_MHPMEVENT26 0x33aU +#define CSR_MHPMEVENT27 0x33bU +#define CSR_MHPMEVENT28 0x33cU +#define CSR_MHPMEVENT29 0x33dU +#define CSR_MHPMEVENT30 0x33eU +#define CSR_MHPMEVENT31 0x33fU +#define CSR_MVENDORID 0xf11U +#define CSR_MARCHID 0xf12U +#define CSR_MIMPID 0xf13U +#define CSR_MHARTID 0xf14U +#define CSR_CYCLEH 0xc80U +#define CSR_TIMEH 0xc81U +#define CSR_INSTRETH 0xc82U +#define CSR_HPMCOUNTER3H 0xc83U +#define CSR_HPMCOUNTER4H 0xc84U +#define CSR_HPMCOUNTER5H 0xc85U +#define CSR_HPMCOUNTER6H 0xc86U +#define CSR_HPMCOUNTER7H 0xc87U +#define CSR_HPMCOUNTER8H 0xc88U +#define CSR_HPMCOUNTER9H 0xc89U +#define CSR_HPMCOUNTER10H 0xc8aU +#define CSR_HPMCOUNTER11H 0xc8bU +#define CSR_HPMCOUNTER12H 0xc8cU +#define CSR_HPMCOUNTER13H 0xc8dU +#define CSR_HPMCOUNTER14H 0xc8eU +#define CSR_HPMCOUNTER15H 0xc8fU +#define CSR_HPMCOUNTER16H 0xc90U +#define CSR_HPMCOUNTER17H 0xc91U +#define CSR_HPMCOUNTER18H 0xc92U +#define CSR_HPMCOUNTER19H 0xc93U +#define CSR_HPMCOUNTER20H 0xc94U +#define CSR_HPMCOUNTER21H 0xc95U +#define CSR_HPMCOUNTER22H 0xc96U +#define CSR_HPMCOUNTER23H 0xc97U +#define CSR_HPMCOUNTER24H 0xc98U +#define CSR_HPMCOUNTER25H 0xc99U +#define CSR_HPMCOUNTER26H 0xc9aU +#define CSR_HPMCOUNTER27H 0xc9bU +#define CSR_HPMCOUNTER28H 0xc9cU +#define CSR_HPMCOUNTER29H 0xc9dU +#define CSR_HPMCOUNTER30H 0xc9eU +#define CSR_HPMCOUNTER31H 0xc9fU +#define CSR_MCYCLEH 0xb80U +#define CSR_MINSTRETH 0xb82U +#define CSR_MHPMCOUNTER3H 0xb83U +#define CSR_MHPMCOUNTER4H 0xb84U +#define CSR_MHPMCOUNTER5H 0xb85U +#define CSR_MHPMCOUNTER6H 0xb86U +#define CSR_MHPMCOUNTER7H 0xb87U +#define CSR_MHPMCOUNTER8H 0xb88U +#define CSR_MHPMCOUNTER9H 0xb89U +#define CSR_MHPMCOUNTER10H 0xb8aU +#define CSR_MHPMCOUNTER11H 0xb8bU +#define CSR_MHPMCOUNTER12H 0xb8cU +#define CSR_MHPMCOUNTER13H 0xb8dU +#define CSR_MHPMCOUNTER14H 0xb8eU +#define CSR_MHPMCOUNTER15H 0xb8fU +#define CSR_MHPMCOUNTER16H 0xb90U +#define CSR_MHPMCOUNTER17H 0xb91U +#define CSR_MHPMCOUNTER18H 0xb92U +#define CSR_MHPMCOUNTER19H 0xb93U +#define CSR_MHPMCOUNTER20H 0xb94U +#define CSR_MHPMCOUNTER21H 0xb95U +#define CSR_MHPMCOUNTER22H 0xb96U +#define CSR_MHPMCOUNTER23H 0xb97U +#define CSR_MHPMCOUNTER24H 0xb98U +#define CSR_MHPMCOUNTER25H 0xb99U +#define CSR_MHPMCOUNTER26H 0xb9aU +#define CSR_MHPMCOUNTER27H 0xb9bU +#define CSR_MHPMCOUNTER28H 0xb9cU +#define CSR_MHPMCOUNTER29H 0xb9dU +#define CSR_MHPMCOUNTER30H 0xb9eU +#define CSR_MHPMCOUNTER31H 0xb9fU +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FAULT_FETCH 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_FAULT_LOAD 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_FAULT_STORE 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_HYPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#endif +#if defined(DECLARE_INSN) +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(uret, MATCH_URET, MASK_URET) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(hret, MATCH_HRET, MASK_HRET) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) +DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) +DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) +DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) +DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) +DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) +DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) +DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) +DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) +DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) +DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) +DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) +DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) +DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) +DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) +DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) +DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) +DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) +DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) +DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) +DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) +DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) +DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) +DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +#endif +#if defined(DECLARE_CSR) +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sie, CSR_SIE) +DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(sscratch, CSR_SSCRATCH) +DECLARE_CSR(sepc, CSR_SEPC) +DECLARE_CSR(scause, CSR_SCAUSE) +DECLARE_CSR(sbadaddr, CSR_SBADADDR) +DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(sptbr, CSR_SPTBR) +DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(medeleg, CSR_MEDELEG) +DECLARE_CSR(mideleg, CSR_MIDELEG) +DECLARE_CSR(mie, CSR_MIE) +DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mscratch, CSR_MSCRATCH) +DECLARE_CSR(mepc, CSR_MEPC) +DECLARE_CSR(mcause, CSR_MCAUSE) +DECLARE_CSR(mbadaddr, CSR_MBADADDR) +DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(dcsr, CSR_DCSR) +DECLARE_CSR(dpc, CSR_DPC) +DECLARE_CSR(dscratch, CSR_DSCRATCH) +DECLARE_CSR(mcycle, CSR_MCYCLE) +DECLARE_CSR(minstret, CSR_MINSTRET) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN) +DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) +DECLARE_CSR(mvendorid, CSR_MVENDORID) +DECLARE_CSR(marchid, CSR_MARCHID) +DECLARE_CSR(mimpid, CSR_MIMPID) +DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mcycleh, CSR_MCYCLEH) +DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) +#endif +#if defined(DECLARE_CAUSE) +DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) +DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH) +DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) +DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) +DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) +DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD) +DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) +DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE) +DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) +DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +#endif diff --git a/Kboot/src/bootloader_lo/include/platform.h b/Kboot/src/bootloader_lo/include/platform.h new file mode 100644 index 0000000..a2800a9 --- /dev/null +++ b/Kboot/src/bootloader_lo/include/platform.h @@ -0,0 +1,98 @@ +/* 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 */ diff --git a/Kboot/src/bootloader_lo/include/spi.h b/Kboot/src/bootloader_lo/include/spi.h new file mode 100644 index 0000000..2646cf8 --- /dev/null +++ b/Kboot/src/bootloader_lo/include/spi.h @@ -0,0 +1,123 @@ +/* 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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _spi +{ + /* SPI Control Register 0 (0x00)*/ + volatile uint32_t ctrlr0; + /* SPI Control Register 1 (0x04)*/ + volatile uint32_t ctrlr1; + /* SPI Enable Register (0x08)*/ + volatile uint32_t ssienr; + /* SPI Microwire Control Register (0x0c)*/ + volatile uint32_t mwcr; + /* SPI Slave Enable Register (0x10)*/ + volatile uint32_t ser; + /* SPI Baud Rate Select (0x14)*/ + volatile uint32_t baudr; + /* SPI Transmit FIFO Threshold Level (0x18)*/ + volatile uint32_t txftlr; + /* SPI Receive FIFO Threshold Level (0x1c)*/ + volatile uint32_t rxftlr; + /* SPI Transmit FIFO Level Register (0x20)*/ + volatile uint32_t txflr; + /* SPI Receive FIFO Level Register (0x24)*/ + volatile uint32_t rxflr; + /* SPI Status Register (0x28)*/ + volatile uint32_t sr; + /* SPI Interrupt Mask Register (0x2c)*/ + volatile uint32_t imr; + /* SPI Interrupt Status Register (0x30)*/ + volatile uint32_t isr; + /* SPI Raw Interrupt Status Register (0x34)*/ + volatile uint32_t risr; + /* SPI Transmit FIFO Overflow Interrupt Clear Register (0x38)*/ + volatile uint32_t txoicr; + /* SPI Receive FIFO Overflow Interrupt Clear Register (0x3c)*/ + volatile uint32_t rxoicr; + /* SPI Receive FIFO Underflow Interrupt Clear Register (0x40)*/ + volatile uint32_t rxuicr; + /* SPI Multi-Master Interrupt Clear Register (0x44)*/ + volatile uint32_t msticr; + /* SPI Interrupt Clear Register (0x48)*/ + volatile uint32_t icr; + /* SPI DMA Control Register (0x4c)*/ + volatile uint32_t dmacr; + /* SPI DMA Transmit Data Level (0x50)*/ + volatile uint32_t dmatdlr; + /* SPI DMA Receive Data Level (0x54)*/ + volatile uint32_t dmardlr; + /* SPI Identification Register (0x58)*/ + volatile uint32_t idr; + /* SPI DWC_ssi component version (0x5c)*/ + volatile uint32_t ssic_version_id; + /* SPI Data Register 0-36 (0x60 -- 0xec)*/ + volatile uint32_t dr[36]; + /* SPI RX Sample Delay Register (0xf0)*/ + volatile uint32_t rx_sample_delay; + /* SPI SPI Control Register (0xf4)*/ + volatile uint32_t spi_ctrlr0; + /* reserved (0xf8)*/ + volatile uint32_t resv; + /* SPI XIP Mode bits (0xfc)*/ + volatile uint32_t xip_mode_bits; + /* SPI XIP INCR transfer opcode (0x100)*/ + volatile uint32_t xip_incr_inst; + /* SPI XIP WRAP transfer opcode (0x104)*/ + volatile uint32_t xip_wrap_inst; + /* SPI XIP Control Register (0x108)*/ + volatile uint32_t xip_ctrl; + /* SPI XIP Slave Enable Register (0x10c)*/ + volatile uint32_t xip_ser; + /* SPI XIP Receive FIFO Overflow Interrupt Clear Register (0x110)*/ + volatile uint32_t xrxoicr; + /* SPI XIP time out register for continuous transfers (0x114)*/ + volatile uint32_t xip_cnt_time_out; + volatile uint32_t endian; +} __attribute__((packed, aligned(4))) spi_t; +/* clang-format on */ + +typedef enum _spi_work_mode +{ + SPI_WORK_MODE_0, + SPI_WORK_MODE_1, + SPI_WORK_MODE_2, + SPI_WORK_MODE_3, +} spi_work_mode_t; + +typedef enum _spi_frame_format +{ + SPI_FF_STANDARD, + SPI_FF_DUAL, + SPI_FF_QUAD, + SPI_FF_OCTAL +} spi_frame_format_t; + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_SPI_H */ diff --git a/Kboot/src/bootloader_lo/include/sysctl.h b/Kboot/src/bootloader_lo/include/sysctl.h new file mode 100644 index 0000000..b37bd64 --- /dev/null +++ b/Kboot/src/bootloader_lo/include/sysctl.h @@ -0,0 +1,886 @@ +/* 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 +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define DEFAULT_CPU_CLOCK 390000000 + + +/** + * @brief System controller register + * + * @note System controller register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | git_id | Git short commit id | + * | 0x04 | clk_freq | System clock base frequency | + * | 0x08 | pll0 | PLL0 controller | + * | 0x0c | pll1 | PLL1 controller | + * | 0x10 | pll2 | PLL2 controller | + * | 0x14 | resv5 | Reserved | + * | 0x18 | pll_lock | PLL lock tester | + * | 0x1c | rom_error | AXI ROM detector | + * | 0x20 | clk_sel0 | Clock select controller0 | + * | 0x24 | clk_sel1 | Clock select controller1 | + * | 0x28 | clk_en_cent | Central clock enable | + * | 0x2c | clk_en_peri | Peripheral clock enable | + * | 0x30 | soft_reset | Soft reset ctrl | + * | 0x34 | peri_reset | Peripheral reset controller | + * | 0x38 | clk_th0 | Clock threshold controller 0 | + * | 0x3c | clk_th1 | Clock threshold controller 1 | + * | 0x40 | clk_th2 | Clock threshold controller 2 | + * | 0x44 | clk_th3 | Clock threshold controller 3 | + * | 0x48 | clk_th4 | Clock threshold controller 4 | + * | 0x4c | clk_th5 | Clock threshold controller 5 | + * | 0x50 | clk_th6 | Clock threshold controller 6 | + * | 0x54 | misc | Miscellaneous controller | + * | 0x58 | peri | Peripheral controller | + * | 0x5c | spi_sleep | SPI sleep controller | + * | 0x60 | reset_status | Reset source status | + * | 0x64 | dma_sel0 | DMA handshake selector | + * | 0x68 | dma_sel1 | DMA handshake selector | + * | 0x6c | power_sel | IO Power Mode Select controller | + * | 0x70 | resv28 | Reserved | + * | 0x74 | resv29 | Reserved | + * | 0x78 | resv30 | Reserved | + * | 0x7c | resv31 | Reserved | + * + */ + +typedef enum _sysctl_pll_t +{ + SYSCTL_PLL0, + SYSCTL_PLL1, + SYSCTL_PLL2, + SYSCTL_PLL_MAX +} sysctl_pll_t; + +typedef enum _sysctl_clock_source_t +{ + SYSCTL_SOURCE_IN0, + SYSCTL_SOURCE_PLL0, + SYSCTL_SOURCE_PLL1, + SYSCTL_SOURCE_PLL2, + SYSCTL_SOURCE_ACLK, + SYSCTL_SOURCE_MAX +} sysctl_clock_source_t; + +typedef enum _sysctl_dma_channel_t +{ + SYSCTL_DMA_CHANNEL_0, + SYSCTL_DMA_CHANNEL_1, + SYSCTL_DMA_CHANNEL_2, + SYSCTL_DMA_CHANNEL_3, + SYSCTL_DMA_CHANNEL_4, + SYSCTL_DMA_CHANNEL_5, + SYSCTL_DMA_CHANNEL_MAX +} sysctl_dma_channel_t; + +typedef enum _sysctl_dma_select_t +{ + SYSCTL_DMA_SELECT_SSI0_RX_REQ, + SYSCTL_DMA_SELECT_SSI0_TX_REQ, + SYSCTL_DMA_SELECT_SSI1_RX_REQ, + SYSCTL_DMA_SELECT_SSI1_TX_REQ, + SYSCTL_DMA_SELECT_SSI2_RX_REQ, + SYSCTL_DMA_SELECT_SSI2_TX_REQ, + SYSCTL_DMA_SELECT_SSI3_RX_REQ, + SYSCTL_DMA_SELECT_SSI3_TX_REQ, + SYSCTL_DMA_SELECT_I2C0_RX_REQ, + SYSCTL_DMA_SELECT_I2C0_TX_REQ, + SYSCTL_DMA_SELECT_I2C1_RX_REQ, + SYSCTL_DMA_SELECT_I2C1_TX_REQ, + SYSCTL_DMA_SELECT_I2C2_RX_REQ, + SYSCTL_DMA_SELECT_I2C2_TX_REQ, + SYSCTL_DMA_SELECT_UART1_RX_REQ, + SYSCTL_DMA_SELECT_UART1_TX_REQ, + SYSCTL_DMA_SELECT_UART2_RX_REQ, + SYSCTL_DMA_SELECT_UART2_TX_REQ, + SYSCTL_DMA_SELECT_UART3_RX_REQ, + SYSCTL_DMA_SELECT_UART3_TX_REQ, + SYSCTL_DMA_SELECT_AES_REQ, + SYSCTL_DMA_SELECT_SHA_RX_REQ, + SYSCTL_DMA_SELECT_AI_RX_REQ, + SYSCTL_DMA_SELECT_FFT_RX_REQ, + SYSCTL_DMA_SELECT_FFT_TX_REQ, + SYSCTL_DMA_SELECT_I2S0_TX_REQ, + SYSCTL_DMA_SELECT_I2S0_RX_REQ, + SYSCTL_DMA_SELECT_I2S1_TX_REQ, + SYSCTL_DMA_SELECT_I2S1_RX_REQ, + SYSCTL_DMA_SELECT_I2S2_TX_REQ, + SYSCTL_DMA_SELECT_I2S2_RX_REQ, + SYSCTL_DMA_SELECT_I2S0_BF_DIR_REQ, + SYSCTL_DMA_SELECT_I2S0_BF_VOICE_REQ, + SYSCTL_DMA_SELECT_MAX +} sysctl_dma_select_t; + +/** + * @brief System controller clock id + */ +typedef enum _sysctl_clock_t +{ + SYSCTL_CLOCK_PLL0, + SYSCTL_CLOCK_PLL1, + SYSCTL_CLOCK_PLL2, + SYSCTL_CLOCK_CPU, + SYSCTL_CLOCK_SRAM0, + SYSCTL_CLOCK_SRAM1, + SYSCTL_CLOCK_APB0, + SYSCTL_CLOCK_APB1, + SYSCTL_CLOCK_APB2, + SYSCTL_CLOCK_ROM, + SYSCTL_CLOCK_DMA, + SYSCTL_CLOCK_AI, + SYSCTL_CLOCK_DVP, + SYSCTL_CLOCK_FFT, + SYSCTL_CLOCK_GPIO, + SYSCTL_CLOCK_SPI0, + SYSCTL_CLOCK_SPI1, + SYSCTL_CLOCK_SPI2, + SYSCTL_CLOCK_SPI3, + SYSCTL_CLOCK_I2S0, + SYSCTL_CLOCK_I2S1, + SYSCTL_CLOCK_I2S2, + SYSCTL_CLOCK_I2C0, + SYSCTL_CLOCK_I2C1, + SYSCTL_CLOCK_I2C2, + SYSCTL_CLOCK_UART1, + SYSCTL_CLOCK_UART2, + SYSCTL_CLOCK_UART3, + SYSCTL_CLOCK_AES, + SYSCTL_CLOCK_FPIOA, + SYSCTL_CLOCK_TIMER0, + SYSCTL_CLOCK_TIMER1, + SYSCTL_CLOCK_TIMER2, + SYSCTL_CLOCK_WDT0, + SYSCTL_CLOCK_WDT1, + SYSCTL_CLOCK_SHA, + SYSCTL_CLOCK_OTP, + SYSCTL_CLOCK_RTC, + SYSCTL_CLOCK_ACLK = 40, + SYSCTL_CLOCK_HCLK, + SYSCTL_CLOCK_IN0, + SYSCTL_CLOCK_MAX +} sysctl_clock_t; + +/** + * @brief System controller clock select id + */ +typedef enum _sysctl_clock_select_t +{ + SYSCTL_CLOCK_SELECT_PLL0_BYPASS, + SYSCTL_CLOCK_SELECT_PLL1_BYPASS, + SYSCTL_CLOCK_SELECT_PLL2_BYPASS, + SYSCTL_CLOCK_SELECT_PLL2, + SYSCTL_CLOCK_SELECT_ACLK, + SYSCTL_CLOCK_SELECT_SPI3, + SYSCTL_CLOCK_SELECT_TIMER0, + SYSCTL_CLOCK_SELECT_TIMER1, + SYSCTL_CLOCK_SELECT_TIMER2, + SYSCTL_CLOCK_SELECT_SPI3_SAMPLE, + SYSCTL_CLOCK_SELECT_MAX = 11 +} sysctl_clock_select_t; + +/** + * @brief System controller clock threshold id + */ +typedef enum _sysctl_threshold_t +{ + SYSCTL_THRESHOLD_ACLK, + SYSCTL_THRESHOLD_APB0, + SYSCTL_THRESHOLD_APB1, + SYSCTL_THRESHOLD_APB2, + SYSCTL_THRESHOLD_SRAM0, + SYSCTL_THRESHOLD_SRAM1, + SYSCTL_THRESHOLD_AI, + SYSCTL_THRESHOLD_DVP, + SYSCTL_THRESHOLD_ROM, + SYSCTL_THRESHOLD_SPI0, + SYSCTL_THRESHOLD_SPI1, + SYSCTL_THRESHOLD_SPI2, + SYSCTL_THRESHOLD_SPI3, + SYSCTL_THRESHOLD_TIMER0, + SYSCTL_THRESHOLD_TIMER1, + SYSCTL_THRESHOLD_TIMER2, + SYSCTL_THRESHOLD_I2S0, + SYSCTL_THRESHOLD_I2S1, + SYSCTL_THRESHOLD_I2S2, + SYSCTL_THRESHOLD_I2S0_M, + SYSCTL_THRESHOLD_I2S1_M, + SYSCTL_THRESHOLD_I2S2_M, + SYSCTL_THRESHOLD_I2C0, + SYSCTL_THRESHOLD_I2C1, + SYSCTL_THRESHOLD_I2C2, + SYSCTL_THRESHOLD_WDT0, + SYSCTL_THRESHOLD_WDT1, + SYSCTL_THRESHOLD_MAX = 28 +} sysctl_threshold_t; + +/** + * @brief System controller reset control id + */ +typedef enum _sysctl_reset_t +{ + SYSCTL_RESET_SOC, + SYSCTL_RESET_ROM, + SYSCTL_RESET_DMA, + SYSCTL_RESET_AI, + SYSCTL_RESET_DVP, + SYSCTL_RESET_FFT, + SYSCTL_RESET_GPIO, + SYSCTL_RESET_SPI0, + SYSCTL_RESET_SPI1, + SYSCTL_RESET_SPI2, + SYSCTL_RESET_SPI3, + SYSCTL_RESET_I2S0, + SYSCTL_RESET_I2S1, + SYSCTL_RESET_I2S2, + SYSCTL_RESET_I2C0, + SYSCTL_RESET_I2C1, + SYSCTL_RESET_I2C2, + SYSCTL_RESET_UART1, + SYSCTL_RESET_UART2, + SYSCTL_RESET_UART3, + SYSCTL_RESET_AES, + SYSCTL_RESET_FPIOA, + SYSCTL_RESET_TIMER0, + SYSCTL_RESET_TIMER1, + SYSCTL_RESET_TIMER2, + SYSCTL_RESET_WDT0, + SYSCTL_RESET_WDT1, + SYSCTL_RESET_SHA, + SYSCTL_RESET_RTC, + SYSCTL_RESET_MAX = 31 +} sysctl_reset_t; + +/** + * @brief System controller power bank id + */ +typedef enum _sysctl_power_bank +{ + SYSCTL_POWER_BANK0, + SYSCTL_POWER_BANK1, + SYSCTL_POWER_BANK2, + SYSCTL_POWER_BANK3, + SYSCTL_POWER_BANK4, + SYSCTL_POWER_BANK5, + SYSCTL_POWER_BANK6, + SYSCTL_POWER_BANK7, + SYSCTL_POWER_BANK_MAX, +} sysctl_power_bank_t; + +/** + * @brief System controller reset control id + */ +typedef enum _sysctl_io_power_mode +{ + SYSCTL_POWER_V33, + SYSCTL_POWER_V18 +} sysctl_io_power_mode_t; + +/** + * @brief System reset status + */ +typedef enum _sysctl_reset_enum_status +{ + SYSCTL_RESET_STATUS_HARD, + SYSCTL_RESET_STATUS_SOFT, + SYSCTL_RESET_STATUS_WDT0, + SYSCTL_RESET_STATUS_WDT1, + SYSCTL_RESET_STATUS_MAX, +} sysctl_reset_enum_status_t; + +/** + * @brief Git short commit id + * + * No. 0 Register (0x00) + */ +typedef struct _sysctl_git_id +{ + uint32_t git_id : 32; +} __attribute__((packed, aligned(4))) sysctl_git_id_t; + +/** + * @brief System clock base frequency + * + * No. 1 Register (0x04) + */ +typedef struct _sysctl_clk_freq +{ + uint32_t clk_freq : 32; +} __attribute__((packed, aligned(4))) sysctl_clk_freq_t; + +/** + * @brief PLL0 controller + * + * No. 2 Register (0x08) + */ +typedef struct _sysctl_pll0 +{ + uint32_t clkr0 : 4; + uint32_t clkf0 : 6; + uint32_t clkod0 : 4; + uint32_t bwadj0 : 6; + uint32_t pll_reset0 : 1; + uint32_t pll_pwrd0 : 1; + uint32_t pll_intfb0 : 1; + uint32_t pll_bypass0 : 1; + uint32_t pll_test0 : 1; + uint32_t pll_out_en0 : 1; + uint32_t pll_test_en : 1; + uint32_t reserved : 5; +} __attribute__((packed, aligned(4))) sysctl_pll0_t; + +/** + * @brief PLL1 controller + * + * No. 3 Register (0x0c) + */ +typedef struct _sysctl_pll1 +{ + uint32_t clkr1 : 4; + uint32_t clkf1 : 6; + uint32_t clkod1 : 4; + uint32_t bwadj1 : 6; + uint32_t pll_reset1 : 1; + uint32_t pll_pwrd1 : 1; + uint32_t pll_intfb1 : 1; + uint32_t pll_bypass1 : 1; + uint32_t pll_test1 : 1; + uint32_t pll_out_en1 : 1; + uint32_t reserved : 6; +} __attribute__((packed, aligned(4))) sysctl_pll1_t; + +/** + * @brief PLL2 controller + * + * No. 4 Register (0x10) + */ +typedef struct _sysctl_pll2 +{ + uint32_t clkr2 : 4; + uint32_t clkf2 : 6; + uint32_t clkod2 : 4; + uint32_t bwadj2 : 6; + uint32_t pll_reset2 : 1; + uint32_t pll_pwrd2 : 1; + uint32_t pll_intfb2 : 1; + uint32_t pll_bypass2 : 1; + uint32_t pll_test2 : 1; + uint32_t pll_out_en2 : 1; + uint32_t pll_ckin_sel2 : 2; + uint32_t reserved : 4; +} __attribute__((packed, aligned(4))) sysctl_pll2_t; + +/** + * @brief PLL lock tester + * + * No. 6 Register (0x18) + */ +typedef struct _sysctl_pll_lock +{ + uint32_t pll_lock0 : 2; + uint32_t pll_slip_clear0 : 1; + uint32_t test_clk_out0 : 1; + uint32_t reserved0 : 4; + uint32_t pll_lock1 : 2; + uint32_t pll_slip_clear1 : 1; + uint32_t test_clk_out1 : 1; + uint32_t reserved1 : 4; + uint32_t pll_lock2 : 2; + uint32_t pll_slip_clear2 : 1; + uint32_t test_clk_out2 : 1; + uint32_t reserved2 : 12; +} __attribute__((packed, aligned(4))) sysctl_pll_lock_t; + +/** + * @brief AXI ROM detector + * + * No. 7 Register (0x1c) + */ +typedef struct _sysctl_rom_error +{ + uint32_t rom_mul_error : 1; + uint32_t rom_one_error : 1; + uint32_t reserved : 30; +} __attribute__((packed, aligned(4))) sysctl_rom_error_t; + +/** + * @brief Clock select controller0 + * + * No. 8 Register (0x20) + */ +typedef struct _sysctl_clk_sel0 +{ + uint32_t aclk_sel : 1; + uint32_t aclk_divider_sel : 2; + uint32_t apb0_clk_sel : 3; + uint32_t apb1_clk_sel : 3; + uint32_t apb2_clk_sel : 3; + uint32_t spi3_clk_sel : 1; + uint32_t timer0_clk_sel : 1; + uint32_t timer1_clk_sel : 1; + uint32_t timer2_clk_sel : 1; + uint32_t reserved : 16; +} __attribute__((packed, aligned(4))) sysctl_clk_sel0_t; + +/** + * @brief Clock select controller1 + * + * No. 9 Register (0x24) + */ +typedef struct _sysctl_clk_sel1 +{ + uint32_t spi3_sample_clk_sel : 1; + uint32_t reserved0 : 30; + uint32_t reserved1 : 1; +} __attribute__((packed, aligned(4))) sysctl_clk_sel1_t; + +/** + * @brief Central clock enable + * + * No. 10 Register (0x28) + */ +typedef struct _sysctl_clk_en_cent +{ + uint32_t cpu_clk_en : 1; + uint32_t sram0_clk_en : 1; + uint32_t sram1_clk_en : 1; + uint32_t apb0_clk_en : 1; + uint32_t apb1_clk_en : 1; + uint32_t apb2_clk_en : 1; + uint32_t reserved : 26; +} __attribute__((packed, aligned(4))) sysctl_clk_en_cent_t; + +/** + * @brief Peripheral clock enable + * + * No. 11 Register (0x2c) + */ +typedef struct _sysctl_clk_en_peri +{ + uint32_t rom_clk_en : 1; + uint32_t dma_clk_en : 1; + uint32_t ai_clk_en : 1; + uint32_t dvp_clk_en : 1; + uint32_t fft_clk_en : 1; + uint32_t gpio_clk_en : 1; + uint32_t spi0_clk_en : 1; + uint32_t spi1_clk_en : 1; + uint32_t spi2_clk_en : 1; + uint32_t spi3_clk_en : 1; + uint32_t i2s0_clk_en : 1; + uint32_t i2s1_clk_en : 1; + uint32_t i2s2_clk_en : 1; + uint32_t i2c0_clk_en : 1; + uint32_t i2c1_clk_en : 1; + uint32_t i2c2_clk_en : 1; + uint32_t uart1_clk_en : 1; + uint32_t uart2_clk_en : 1; + uint32_t uart3_clk_en : 1; + uint32_t aes_clk_en : 1; + uint32_t fpioa_clk_en : 1; + uint32_t timer0_clk_en : 1; + uint32_t timer1_clk_en : 1; + uint32_t timer2_clk_en : 1; + uint32_t wdt0_clk_en : 1; + uint32_t wdt1_clk_en : 1; + uint32_t sha_clk_en : 1; + uint32_t otp_clk_en : 1; + uint32_t reserved : 1; + uint32_t rtc_clk_en : 1; + uint32_t reserved0 : 2; +} __attribute__((packed, aligned(4))) sysctl_clk_en_peri_t; + +/** + * @brief Soft reset ctrl + * + * No. 12 Register (0x30) + */ +typedef struct _sysctl_soft_reset +{ + uint32_t soft_reset : 1; + uint32_t reserved : 31; +} __attribute__((packed, aligned(4))) sysctl_soft_reset_t; + +/** + * @brief Peripheral reset controller + * + * No. 13 Register (0x34) + */ +typedef struct _sysctl_peri_reset +{ + uint32_t rom_reset : 1; + uint32_t dma_reset : 1; + uint32_t ai_reset : 1; + uint32_t dvp_reset : 1; + uint32_t fft_reset : 1; + uint32_t gpio_reset : 1; + uint32_t spi0_reset : 1; + uint32_t spi1_reset : 1; + uint32_t spi2_reset : 1; + uint32_t spi3_reset : 1; + uint32_t i2s0_reset : 1; + uint32_t i2s1_reset : 1; + uint32_t i2s2_reset : 1; + uint32_t i2c0_reset : 1; + uint32_t i2c1_reset : 1; + uint32_t i2c2_reset : 1; + uint32_t uart1_reset : 1; + uint32_t uart2_reset : 1; + uint32_t uart3_reset : 1; + uint32_t aes_reset : 1; + uint32_t fpioa_reset : 1; + uint32_t timer0_reset : 1; + uint32_t timer1_reset : 1; + uint32_t timer2_reset : 1; + uint32_t wdt0_reset : 1; + uint32_t wdt1_reset : 1; + uint32_t sha_reset : 1; + uint32_t reserved : 2; + uint32_t rtc_reset : 1; + uint32_t reserved0 : 2; +} __attribute__((packed, aligned(4))) sysctl_peri_reset_t; + +/** + * @brief Clock threshold controller 0 + * + * No. 14 Register (0x38) + */ +typedef struct _sysctl_clk_th0 +{ + uint32_t sram0_gclk_threshold : 4; + uint32_t sram1_gclk_threshold : 4; + uint32_t ai_gclk_threshold : 4; + uint32_t dvp_gclk_threshold : 4; + uint32_t rom_gclk_threshold : 4; + uint32_t reserved : 12; +} __attribute__((packed, aligned(4))) sysctl_clk_th0_t; + +/** + * @brief Clock threshold controller 1 + * + * No. 15 Register (0x3c) + */ +typedef struct _sysctl_clk_th1 +{ + uint32_t spi0_clk_threshold : 8; + uint32_t spi1_clk_threshold : 8; + uint32_t spi2_clk_threshold : 8; + uint32_t spi3_clk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th1_t; + +/** + * @brief Clock threshold controller 2 + * + * No. 16 Register (0x40) + */ +typedef struct _sysctl_clk_th2 +{ + uint32_t timer0_clk_threshold : 8; + uint32_t timer1_clk_threshold : 8; + uint32_t timer2_clk_threshold : 8; + uint32_t reserved : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th2_t; + +/** + * @brief Clock threshold controller 3 + * + * No. 17 Register (0x44) + */ +typedef struct _sysctl_clk_th3 +{ + uint32_t i2s0_clk_threshold : 16; + uint32_t i2s1_clk_threshold : 16; +} __attribute__((packed, aligned(4))) sysctl_clk_th3_t; + +/** + * @brief Clock threshold controller 4 + * + * No. 18 Register (0x48) + */ +typedef struct _sysctl_clk_th4 +{ + uint32_t i2s2_clk_threshold : 16; + uint32_t i2s0_mclk_threshold : 8; + uint32_t i2s1_mclk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th4_t; + +/** + * @brief Clock threshold controller 5 + * + * No. 19 Register (0x4c) + */ +typedef struct _sysctl_clk_th5 +{ + uint32_t i2s2_mclk_threshold : 8; + uint32_t i2c0_clk_threshold : 8; + uint32_t i2c1_clk_threshold : 8; + uint32_t i2c2_clk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th5_t; + +/** + * @brief Clock threshold controller 6 + * + * No. 20 Register (0x50) + */ +typedef struct _sysctl_clk_th6 +{ + uint32_t wdt0_clk_threshold : 8; + uint32_t wdt1_clk_threshold : 8; + uint32_t reserved0 : 8; + uint32_t reserved1 : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th6_t; + +/** + * @brief Miscellaneous controller + * + * No. 21 Register (0x54) + */ +typedef struct _sysctl_misc +{ + uint32_t debug_sel : 6; + uint32_t reserved0 : 4; + uint32_t spi_dvp_data_enable : 1; + uint32_t reserved1 : 21; +} __attribute__((packed, aligned(4))) sysctl_misc_t; + +/** + * @brief Peripheral controller + * + * No. 22 Register (0x58) + */ +typedef struct _sysctl_peri +{ + uint32_t timer0_pause : 1; + uint32_t timer1_pause : 1; + uint32_t timer2_pause : 1; + uint32_t timer3_pause : 1; + uint32_t timer4_pause : 1; + uint32_t timer5_pause : 1; + uint32_t timer6_pause : 1; + uint32_t timer7_pause : 1; + uint32_t timer8_pause : 1; + uint32_t timer9_pause : 1; + uint32_t timer10_pause : 1; + uint32_t timer11_pause : 1; + uint32_t spi0_xip_en : 1; + uint32_t spi1_xip_en : 1; + uint32_t spi2_xip_en : 1; + uint32_t spi3_xip_en : 1; + uint32_t spi0_clk_bypass : 1; + uint32_t spi1_clk_bypass : 1; + uint32_t spi2_clk_bypass : 1; + uint32_t i2s0_clk_bypass : 1; + uint32_t i2s1_clk_bypass : 1; + uint32_t i2s2_clk_bypass : 1; + uint32_t jtag_clk_bypass : 1; + uint32_t dvp_clk_bypass : 1; + uint32_t debug_clk_bypass : 1; + uint32_t reserved0 : 1; + uint32_t reserved1 : 6; +} __attribute__((packed, aligned(4))) sysctl_peri_t; + +/** + * @brief SPI sleep controller + * + * No. 23 Register (0x5c) + */ +typedef struct _sysctl_spi_sleep +{ + uint32_t ssi0_sleep : 1; + uint32_t ssi1_sleep : 1; + uint32_t ssi2_sleep : 1; + uint32_t ssi3_sleep : 1; + uint32_t reserved : 28; +} __attribute__((packed, aligned(4))) sysctl_spi_sleep_t; + +/** + * @brief Reset source status + * + * No. 24 Register (0x60) + */ +typedef struct _sysctl_reset_status +{ + uint32_t reset_sts_clr : 1; + uint32_t pin_reset_sts : 1; + uint32_t wdt0_reset_sts : 1; + uint32_t wdt1_reset_sts : 1; + uint32_t soft_reset_sts : 1; + uint32_t reserved : 27; +} __attribute__((packed, aligned(4))) sysctl_reset_status_t; + +/** + * @brief DMA handshake selector + * + * No. 25 Register (0x64) + */ +typedef struct _sysctl_dma_sel0 +{ + uint32_t dma_sel0 : 6; + uint32_t dma_sel1 : 6; + uint32_t dma_sel2 : 6; + uint32_t dma_sel3 : 6; + uint32_t dma_sel4 : 6; + uint32_t reserved : 2; +} __attribute__((packed, aligned(4))) sysctl_dma_sel0_t; + +/** + * @brief DMA handshake selector + * + * No. 26 Register (0x68) + */ +typedef struct _sysctl_dma_sel1 +{ + uint32_t dma_sel5 : 6; + uint32_t reserved : 26; +} __attribute__((packed, aligned(4))) sysctl_dma_sel1_t; + +/** + * @brief IO Power Mode Select controller + * + * No. 27 Register (0x6c) + */ +typedef struct _sysctl_power_sel +{ + uint32_t power_mode_sel0 : 1; + uint32_t power_mode_sel1 : 1; + uint32_t power_mode_sel2 : 1; + uint32_t power_mode_sel3 : 1; + uint32_t power_mode_sel4 : 1; + uint32_t power_mode_sel5 : 1; + uint32_t power_mode_sel6 : 1; + uint32_t power_mode_sel7 : 1; + uint32_t reserved : 24; +} __attribute__((packed, aligned(4))) sysctl_power_sel_t; + +/** + * @brief System controller object + * + * The System controller is a peripheral device mapped in the + * internal memory map, discoverable in the Configuration String. + * It is responsible for low-level configuration of all system + * related peripheral device. It contain PLL controller, clock + * controller, reset controller, DMA handshake controller, SPI + * controller, timer controller, WDT controller and sleep + * controller. + */ +typedef struct _sysctl +{ + /* No. 0 (0x00): Git short commit id */ + sysctl_git_id_t git_id; + /* No. 1 (0x04): System clock base frequency */ + sysctl_clk_freq_t clk_freq; + /* No. 2 (0x08): PLL0 controller */ + sysctl_pll0_t pll0; + /* No. 3 (0x0c): PLL1 controller */ + sysctl_pll1_t pll1; + /* No. 4 (0x10): PLL2 controller */ + sysctl_pll2_t pll2; + /* No. 5 (0x14): Reserved */ + uint32_t resv5; + /* No. 6 (0x18): PLL lock tester */ + sysctl_pll_lock_t pll_lock; + /* No. 7 (0x1c): AXI ROM detector */ + sysctl_rom_error_t rom_error; + /* No. 8 (0x20): Clock select controller0 */ + sysctl_clk_sel0_t clk_sel0; + /* No. 9 (0x24): Clock select controller1 */ + sysctl_clk_sel1_t clk_sel1; + /* No. 10 (0x28): Central clock enable */ + sysctl_clk_en_cent_t clk_en_cent; + /* No. 11 (0x2c): Peripheral clock enable */ + sysctl_clk_en_peri_t clk_en_peri; + /* No. 12 (0x30): Soft reset ctrl */ + sysctl_soft_reset_t soft_reset; + /* No. 13 (0x34): Peripheral reset controller */ + sysctl_peri_reset_t peri_reset; + /* No. 14 (0x38): Clock threshold controller 0 */ + sysctl_clk_th0_t clk_th0; + /* No. 15 (0x3c): Clock threshold controller 1 */ + sysctl_clk_th1_t clk_th1; + /* No. 16 (0x40): Clock threshold controller 2 */ + sysctl_clk_th2_t clk_th2; + /* No. 17 (0x44): Clock threshold controller 3 */ + sysctl_clk_th3_t clk_th3; + /* No. 18 (0x48): Clock threshold controller 4 */ + sysctl_clk_th4_t clk_th4; + /* No. 19 (0x4c): Clock threshold controller 5 */ + sysctl_clk_th5_t clk_th5; + /* No. 20 (0x50): Clock threshold controller 6 */ + sysctl_clk_th6_t clk_th6; + /* No. 21 (0x54): Miscellaneous controller */ + sysctl_misc_t misc; + /* No. 22 (0x58): Peripheral controller */ + sysctl_peri_t peri; + /* No. 23 (0x5c): SPI sleep controller */ + sysctl_spi_sleep_t spi_sleep; + /* No. 24 (0x60): Reset source status */ + sysctl_reset_status_t reset_status; + /* No. 25 (0x64): DMA handshake selector */ + sysctl_dma_sel0_t dma_sel0; + /* No. 26 (0x68): DMA handshake selector */ + sysctl_dma_sel1_t dma_sel1; + /* No. 27 (0x6c): IO Power Mode Select controller */ + sysctl_power_sel_t power_sel; + /* No. 28 (0x70): Reserved */ + uint32_t resv28; + /* No. 29 (0x74): Reserved */ + uint32_t resv29; + /* No. 30 (0x78): Reserved */ + uint32_t resv30; + /* No. 31 (0x7c): Reserved */ + uint32_t resv31; +} __attribute__((packed, aligned(4))) sysctl_t; + +/** + * @brief Abstruct PLL struct + */ +typedef struct _sysctl_general_pll +{ + uint32_t clkr : 4; + uint32_t clkf : 6; + uint32_t clkod : 4; + uint32_t bwadj : 6; + uint32_t pll_reset : 1; + uint32_t pll_pwrd : 1; + uint32_t pll_intfb : 1; + uint32_t pll_bypass : 1; + uint32_t pll_test : 1; + uint32_t pll_out_en : 1; + uint32_t pll_ckin_sel : 2; + uint32_t reserved : 4; +} __attribute__((packed, aligned(4))) sysctl_general_pll_t; + +/** + * @brief System controller object instanse + */ +extern volatile sysctl_t *const sysctl; + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_SYSCTL_H */ diff --git a/Kboot/src/bootloader_lo/main.c b/Kboot/src/bootloader_lo/main.c new file mode 100644 index 0000000..2897bce --- /dev/null +++ b/Kboot/src/bootloader_lo/main.c @@ -0,0 +1,191 @@ +/* Copyright 2019 LoBo + * + * K210 Bootloader stage_0 + * ver. 1.4.1, 01/2020 + * + * 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. + */ + +/* + * ----------------------------------------------------------------------------- + * KBoot SPI Flash layout: + * ----------------------------------------------------------------------------- + * From To Length Comment + * ----------------------------------------------------------------------------- + * 0x00000000 0x00000FFF 4K bootloader stage_0 code + * 0x00001000 0x00003FFF 12K bootloader stage_1 code + * 0x00004000 0x00004FFF 4K boot configuration sector (256B used) + * 0x00005000 0x00005FFF 4K boot configuration sector BACKUP (256B used) + * 0x00006000 0x0000FFFF 40K reserved + * ----------------------------------------------------------------------------- + * 0x00010000 default application, optional, recommended + * flash_end user area, app code, file systems, data... + * ----------------------------------------------------------------------------- + */ + + +#include "spi.h" +#include "sysctl.h" +#include "encoding.h" + +// Constants + +#define BOOTHI_FLASH_ADDR 0x00001005 // stage_1 bootloader code Flash address +#define BOOTHI_SRAM_ADDR 0x805E0000 // stage_1 bootloader code SRAM address +#define BOOTHI_SIZE 0x00003000 // stage_1 bootloader code size (max) + +// K210 ROM functions +typedef int rom_print_func(const char * restrict format, ... ); +rom_print_func *rom_printf = (rom_print_func*)0x88001418; // fixed address in ROM +rom_print_func *rom_printk = (rom_print_func*)0x880016b0; // fixed address in ROM + +// Variables +volatile sysctl_t *const sysctl = (volatile sysctl_t *)SYSCTL_BASE_ADDR; +static volatile spi_t *spi_handle = (volatile spi_t *)SPI3_BASE_ADDR; + +static uint64_t boothi_start = BOOTHI_SRAM_ADDR; +static uint8_t *boothi_flash_ptr = (uint8_t *)SPI3_BASE_ADDR+BOOTHI_FLASH_ADDR; +static uint8_t *boothi_sram_ptr = (uint8_t *)BOOTHI_SRAM_ADDR; +static uint32_t i = 0; +static uint32_t core0_sync = 0; +static uint32_t core1_sync = 0; + +/* + * After the K210 is reset the 'booltloder_lo.bin' code is loaded from SPI Flash + * to SRAM address 0x80000000 by ROM code and executed. + * This is the first location containing the K210 code! + * ------------------------------------------------------------- + * We come here twice: running on core #0 and running on core #1 + * ------------------------------------------------------------- + */ + +//============ +int main(void) +{ + // Initialize bss data to 0, not needed as no bss data is used + /* + extern unsigned int _bss; + extern unsigned int _ebss; + unsigned int *dst; + dst = &_bss; + while(dst < &_ebss) + *dst++ = 0; + */ + + // Check the core we are running on + i = read_csr(mhartid); + //--------------------------------------------------------- + if (i != 0) { + // ============================ + // ==== Running on core #1 ==== + // ============================ + core0_sync = 1; + // wait for synchronization with core #0 + while (core1_sync == 0) { + asm("nop"); + } + /* + * core #0 is done, the 2nd part of kboot is transfered + * to the high sram, continue the execution there + * + * each core has separate instruction cache + * we must clear it before continuing + */ + asm("fence"); // D-Cache; this may not be necessary, but it looks it doesn't hurt if it is executed + asm("fence.i"); // I-Cache + // continue at 2nd part of kboot at high sram + asm ("jr %0" : : "r"(boothi_start)); + + // This should never be reached! + while (1) { + asm("nop"); + } + } + //--------------------------------------------------------- + + // ============================ + // ==== Running on core #0 ==== + // ============================ + + // Without this command every character is printed twice (why !?) + rom_printf(NULL); + // wait for synchronization with core #1 + while (core0_sync == 0) { + asm("nop"); + } + + // ---------------------------------------------------------------------------------------------- + // === Initialize SPI Flash driver === + // spi clock init (SPI3 clock source is PLL0/2, 390 MHz) + sysctl->clk_sel0.spi3_clk_sel = 1; + sysctl->clk_en_peri.spi3_clk_en = 1; + sysctl->clk_th1.spi3_clk_threshold = 0; + + // spi3 init + // sets spi clock to 43.333333 MHz + spi_handle->baudr = 9; + spi_handle->imr = 0x00; + spi_handle->dmacr = 0x00; + spi_handle->dmatdlr = 0x10; + spi_handle->dmardlr = 0x00; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + spi_handle->ctrlr0 = (SPI_WORK_MODE_0 << 8) | (SPI_FF_QUAD << 22) | (7 << 0); + spi_handle->spi_ctrlr0 = 0; + spi_handle->endian = 0; + + // Enable XIP mode + 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; + // ---------------------------------------------------------------------------------------------- + + // ========================================================================== + // === Copy the 2nd part of kboot code from flash to SRAM at high address === + // ========================================================================== + for (i = 0; i < BOOTHI_SIZE; i++) { + *boothi_sram_ptr++ = *boothi_flash_ptr++; + } + + // === JUMP to stage_1 code start === + // Leave XIP mode enabled + /* + * each core has separate instruction cache + * we must clear it before continuing + * Quote: + The FENCE.I instruction is used to synchronize the instruction and data streams. + RISC-V does not guarantee that stores to instruction memory will be made visible to instruction fetches + on a RISC-V hart until that hart executes a FENCE.I instruction. + A FENCE.I instruction ensures that a subsequent instruction fetch on a RISC-V hart + will see any previous data stores already visible to the same RISC-V hart. + FENCE.I does not ensure that other RISC-V harts’ instruction fetches will + observe the local hart’s stores in a multiprocessor system. + To make a store to instruction memory visible to all RISC-V harts, + the writing hart has to execute a data FENCE before requesting that all remote RISC-V harts execute a FENCE.I. + */ + + core1_sync = 1; + asm("fence"); // D-Cache; this may not be necessary, but it looks it doesn't hurt if it is executed + asm("fence.i"); // I-Cache + asm ("jr %0" : : "r"(boothi_start)); + + // This should never be reached! + while (1) { + asm("nop"); + } + return 0; +} diff --git a/firmware/MicroPython.bin b/firmware/MicroPython.bin index c6d9d70..754c215 100755 Binary files a/firmware/MicroPython.bin and b/firmware/MicroPython.bin differ diff --git a/firmware/MicroPython.kfpkg b/firmware/MicroPython.kfpkg index 73399f3..15c9929 100644 Binary files a/firmware/MicroPython.kfpkg and b/firmware/MicroPython.kfpkg differ diff --git a/firmware/MicroPython_firmwares.zip b/firmware/MicroPython_firmwares.zip index 910e1b7..9435ff4 100644 Binary files a/firmware/MicroPython_firmwares.zip and b/firmware/MicroPython_firmwares.zip differ diff --git a/firmware/README.md b/firmware/README.md index 807fc5b..3ede0ef 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -6,6 +6,7 @@ Three prebuilt firmwares are provided: * `default` default configuration, no sqlite module, one MicroPython task; in this directory * `sqlite` default configuration, sqlite module included, one MicroPython task; in `sqlite` directory * `twotasks` no KPU (8 MB SRAM used), sqlite module included, two MicroPython task; in `twotasks` directory +* `default` default configuration, no sqlite module, one MicroPython task, **OTA enabled**; in `ota` directory To flash the pre-built firmware to your K210 board, run (in this directory): @@ -14,8 +15,19 @@ To flash the pre-built firmware to your K210 board, run (in this directory): ``` Change */dev/ttyUSB0* to the port used to connect to the board if needed.
-You can replace `MicroPython.bin` with `sqlite/MicroPython.bin` or `twotasks/MicroPython.bin` to flash another firmware. +You can replace `MicroPython.bin` with `sqlite/MicroPython.bin`, `twotasks/MicroPython.bin` or `ota/MicroPython.bin`to flash another firmware. `MicroPython.kfpkg` is also provided which contains prebuilt LittleFS internal file system.
To flash it, just replace `MicroPython.bin` with `MicroPython.kfpkg`. + +## Flashing OTA firmware + +**OTA firmware** is suposed to run with **KBoot** bootloader.
+_Kboot bootloader_ is included in `ota/MicroPython.kfpkg`, when flashing for the **first time**, always use **`MicroPython.kfpkg`**, not a `MicroPython.bin`!
+ +After the _Kboot bootloader_ is flashed, you can later flash only the MicroPython binary using the command: + +``` +./kflash.py -p /dev/ttyUSB0 -a 65536 -b 2000000 -t MicroPython.bin +``` diff --git a/firmware/kflash.py b/firmware/kflash.py index d694ff1..9e9117c 100755 --- a/firmware/kflash.py +++ b/firmware/kflash.py @@ -1225,6 +1225,8 @@ def flash_firmware(self, firmware_bin, aes_key = None, address_offset = 0, sha25 else: KTool.log(INFO_MSG, 'Flashed {} B [{} chunks of {}B] ({:08X}~{:08X}) in {:.3f}s'.format( firmware_length, total_chunk, chunk_size, address_offset, curr_address+chunk_size-1, time.time()-time_start), BASH_TIPS['DEFAULT']) + if (sha256Prefix == True): + KTool.log(INFO_MSG, 'SHA256: {}'.format(binascii.hexlify(sha256_hash)), BASH_TIPS['DEFAULT']) # ============================== diff --git a/firmware/ktool.py b/firmware/ktool.py index d694ff1..9e9117c 100755 --- a/firmware/ktool.py +++ b/firmware/ktool.py @@ -1225,6 +1225,8 @@ def flash_firmware(self, firmware_bin, aes_key = None, address_offset = 0, sha25 else: KTool.log(INFO_MSG, 'Flashed {} B [{} chunks of {}B] ({:08X}~{:08X}) in {:.3f}s'.format( firmware_length, total_chunk, chunk_size, address_offset, curr_address+chunk_size-1, time.time()-time_start), BASH_TIPS['DEFAULT']) + if (sha256Prefix == True): + KTool.log(INFO_MSG, 'SHA256: {}'.format(binascii.hexlify(sha256_hash)), BASH_TIPS['DEFAULT']) # ============================== diff --git a/firmware/ota/MicroPython.bin b/firmware/ota/MicroPython.bin new file mode 100755 index 0000000..3eb5874 Binary files /dev/null and b/firmware/ota/MicroPython.bin differ diff --git a/firmware/ota/MicroPython.kfpkg b/firmware/ota/MicroPython.kfpkg new file mode 100644 index 0000000..a76db09 Binary files /dev/null and b/firmware/ota/MicroPython.kfpkg differ diff --git a/firmware/sqlite/MicroPython.bin b/firmware/sqlite/MicroPython.bin index 1833a08..6d24fee 100755 Binary files a/firmware/sqlite/MicroPython.bin and b/firmware/sqlite/MicroPython.bin differ diff --git a/firmware/sqlite/MicroPython.kfpkg b/firmware/sqlite/MicroPython.kfpkg index 0494658..e72dcf3 100644 Binary files a/firmware/sqlite/MicroPython.kfpkg and b/firmware/sqlite/MicroPython.kfpkg differ diff --git a/firmware/twotasks/MicroPython.bin b/firmware/twotasks/MicroPython.bin index edfbd6c..c66726d 100755 Binary files a/firmware/twotasks/MicroPython.bin and b/firmware/twotasks/MicroPython.bin differ diff --git a/firmware/twotasks/MicroPython.kfpkg b/firmware/twotasks/MicroPython.kfpkg index f001e6b..c66950d 100644 Binary files a/firmware/twotasks/MicroPython.kfpkg and b/firmware/twotasks/MicroPython.kfpkg differ diff --git a/k210-freertos/.config b/k210-freertos/.config index 38f8039..24e02e8 100644 --- a/k210-freertos/.config +++ b/k210-freertos/.config @@ -12,14 +12,15 @@ CONFIG_FIRMWARE_SIZE_TYPE=2 CONFIG_FIRMWARE_SIZE_3_MB=y # CONFIG_FIRMWARE_SIZE_3_5_MB is not set CONFIG_MICROPY_K210_KPU_USED=y -CONFIG_MICRO_PY_FREE_RTOS_RESERVED=896 +# CONFIG_MICROPY_USE_OTA is not set +CONFIG_MICRO_PY_FREE_RTOS_RESERVED=768 CONFIG_MICROPY_HW_BOARD_NAME="Sipeed_board" CONFIG_MICROPY_HW_MCU_NAME="Kendryte-K210" CONFIG_MICROPY_PY_USE_LOG_COLORS=y # CONFIG_MICROPY_USE_TWO_MAIN_TASKS is not set CONFIG_MICROPY_ENABLE_PYSTACK=y CONFIG_MICROPY_PY_THREAD_GIL_VM_DIVISOR=32 -CONFIG_MICRO_PY_BOOT_MENU_PIN=15 +CONFIG_MICRO_PY_BOOT_MENU_PIN=0 CONFIG_MICROPY_WQ25XXX_MAX_SPEED=40 # CONFIG_MICROPY_BANK67_3V is not set CONFIG_MICRO_PY_DEFAULT_BAUDRATE=115200 diff --git a/k210-freertos/.config.default b/k210-freertos/.config.default index 38f8039..24e02e8 100644 --- a/k210-freertos/.config.default +++ b/k210-freertos/.config.default @@ -12,14 +12,15 @@ CONFIG_FIRMWARE_SIZE_TYPE=2 CONFIG_FIRMWARE_SIZE_3_MB=y # CONFIG_FIRMWARE_SIZE_3_5_MB is not set CONFIG_MICROPY_K210_KPU_USED=y -CONFIG_MICRO_PY_FREE_RTOS_RESERVED=896 +# CONFIG_MICROPY_USE_OTA is not set +CONFIG_MICRO_PY_FREE_RTOS_RESERVED=768 CONFIG_MICROPY_HW_BOARD_NAME="Sipeed_board" CONFIG_MICROPY_HW_MCU_NAME="Kendryte-K210" CONFIG_MICROPY_PY_USE_LOG_COLORS=y # CONFIG_MICROPY_USE_TWO_MAIN_TASKS is not set CONFIG_MICROPY_ENABLE_PYSTACK=y CONFIG_MICROPY_PY_THREAD_GIL_VM_DIVISOR=32 -CONFIG_MICRO_PY_BOOT_MENU_PIN=15 +CONFIG_MICRO_PY_BOOT_MENU_PIN=0 CONFIG_MICROPY_WQ25XXX_MAX_SPEED=40 # CONFIG_MICROPY_BANK67_3V is not set CONFIG_MICRO_PY_DEFAULT_BAUDRATE=115200 diff --git a/k210-freertos/.config.ota b/k210-freertos/.config.ota new file mode 100644 index 0000000..580759f --- /dev/null +++ b/k210-freertos/.config.ota @@ -0,0 +1,67 @@ +# +# Automatically generated file; DO NOT EDIT. +# MicroPython for Kendryte K210 +# + +# +# General settings +# +CONFIG_FIRMWARE_SIZE_TYPE=2 +# CONFIG_FIRMWARE_SIZE_2_MB is not set +# CONFIG_FIRMWARE_SIZE_2_5_MB is not set +CONFIG_FIRMWARE_SIZE_3_MB=y +# CONFIG_FIRMWARE_SIZE_3_5_MB is not set +CONFIG_MICROPY_K210_KPU_USED=y +CONFIG_MICROPY_USE_OTA=y +CONFIG_MICRO_PY_MBOOT_PIN=-1 +CONFIG_MICRO_PY_FREE_RTOS_RESERVED=768 +CONFIG_MICROPY_HW_BOARD_NAME="Sipeed_board" +CONFIG_MICROPY_HW_MCU_NAME="Kendryte-K210" +CONFIG_MICROPY_PY_USE_LOG_COLORS=y +# CONFIG_MICROPY_USE_TWO_MAIN_TASKS is not set +CONFIG_MICROPY_ENABLE_PYSTACK=y +CONFIG_MICROPY_PY_THREAD_GIL_VM_DIVISOR=32 +CONFIG_MICRO_PY_BOOT_MENU_PIN=0 +CONFIG_MICROPY_WQ25XXX_MAX_SPEED=40 +# CONFIG_MICROPY_BANK67_3V is not set +CONFIG_MICRO_PY_DEFAULT_BAUDRATE=115200 +CONFIG_MICRO_PY_DEFAULT_BAUDRATE0=y +# CONFIG_MICRO_PY_DEFAULT_BAUDRATE1 is not set +# CONFIG_MICRO_PY_DEFAULT_BAUDRATE2 is not set +# CONFIG_MICRO_PY_DEFAULT_BAUDRATE3 is not set +# CONFIG_MICRO_PY_DEFAULT_BAUDRATE4 is not set +# CONFIG_MICRO_PY_DEFAULT_BAUDRATE5 is not set +# CONFIG_MICRO_PY_DEFAULT_BAUDRATE6 is not set +# CONFIG_MICRO_PY_DEFAULT_BAUDRATE7 is not set + +# +# File systems +# +CONFIG_MICRO_PY_FLASH_SIZE=16 +CONFIG_MICRO_PY_FLASHFS_START_ADDRESS=5 +CONFIG_MICRO_PY_FLASHFS_SIZE=10 +CONFIG_MICROPY_FILESYSTEM_TYPE=0 +CONFIG_MICRO_PY_FLASHFS_LITTLEFS=y +# CONFIG_MICRO_PY_FLASHFS_SPIFFS is not set + +# +# SD Card config +# +CONFIG_MICRO_PY_SD_MISO=26 +CONFIG_MICRO_PY_SD_MOSI=28 +CONFIG_MICRO_PY_SD_SCLK=27 +CONFIG_MICRO_PY_SD_CS=29 + +# +# MicroPython modules +# +# CONFIG_MICROPY_PY_USE_SQLITE is not set +CONFIG_MICROPY_USE_DISPLAY=y +CONFIG_MICROPY_USE_TFT=y +CONFIG_MICROPY_USE_EPD=y +CONFIG_MICROPY_USE_CAMERA=y +CONFIG_MICROPY_PY_USE_GSM=y +CONFIG_MICROPY_PY_USE_WIFI=y +CONFIG_MICROPY_PY_USE_MQTT=y +CONFIG_MICROPY_PY_USE_REQUESTS=y +CONFIG_MICROPY_PY_USE_ULAB=y diff --git a/k210-freertos/.config.sqlite b/k210-freertos/.config.sqlite index 4c380da..036fe13 100644 --- a/k210-freertos/.config.sqlite +++ b/k210-freertos/.config.sqlite @@ -12,14 +12,15 @@ CONFIG_FIRMWARE_SIZE_TYPE=2 CONFIG_FIRMWARE_SIZE_3_MB=y # CONFIG_FIRMWARE_SIZE_3_5_MB is not set CONFIG_MICROPY_K210_KPU_USED=y -CONFIG_MICRO_PY_FREE_RTOS_RESERVED=896 +# CONFIG_MICROPY_USE_OTA is not set +CONFIG_MICRO_PY_FREE_RTOS_RESERVED=768 CONFIG_MICROPY_HW_BOARD_NAME="Sipeed_board" CONFIG_MICROPY_HW_MCU_NAME="Kendryte-K210" CONFIG_MICROPY_PY_USE_LOG_COLORS=y # CONFIG_MICROPY_USE_TWO_MAIN_TASKS is not set CONFIG_MICROPY_ENABLE_PYSTACK=y CONFIG_MICROPY_PY_THREAD_GIL_VM_DIVISOR=32 -CONFIG_MICRO_PY_BOOT_MENU_PIN=15 +CONFIG_MICRO_PY_BOOT_MENU_PIN=0 CONFIG_MICROPY_WQ25XXX_MAX_SPEED=40 # CONFIG_MICROPY_BANK67_3V is not set CONFIG_MICRO_PY_DEFAULT_BAUDRATE=115200 diff --git a/k210-freertos/.config.twotasks b/k210-freertos/.config.twotasks index 8ba861c..6beb981 100644 --- a/k210-freertos/.config.twotasks +++ b/k210-freertos/.config.twotasks @@ -12,6 +12,7 @@ CONFIG_FIRMWARE_SIZE_TYPE=2 CONFIG_FIRMWARE_SIZE_3_MB=y # CONFIG_FIRMWARE_SIZE_3_5_MB is not set # CONFIG_MICROPY_K210_KPU_USED is not set +# CONFIG_MICROPY_USE_OTA is not set CONFIG_MICRO_PY_FREE_RTOS_RESERVED=896 CONFIG_MICROPY_HW_BOARD_NAME="Sipeed_board" CONFIG_MICROPY_HW_MCU_NAME="Kendryte-K210" @@ -19,7 +20,7 @@ CONFIG_MICROPY_PY_USE_LOG_COLORS=y CONFIG_MICROPY_USE_TWO_MAIN_TASKS=y CONFIG_MICROPY_ENABLE_PYSTACK=y CONFIG_MICROPY_PY_THREAD_GIL_VM_DIVISOR=32 -CONFIG_MICRO_PY_BOOT_MENU_PIN=15 +CONFIG_MICRO_PY_BOOT_MENU_PIN=0 CONFIG_MICROPY_WQ25XXX_MAX_SPEED=40 # CONFIG_MICROPY_BANK67_3V is not set CONFIG_MICRO_PY_DEFAULT_BAUDRATE=115200 diff --git a/k210-freertos/BUILD.sh b/k210-freertos/BUILD.sh index 35e4212..c4113de 100755 --- a/k210-freertos/BUILD.sh +++ b/k210-freertos/BUILD.sh @@ -34,6 +34,7 @@ J_OPTION= CREATE_DUMP="" RUN_MENUCONFIG="" USE_CONFIG_FILE="" +CREATE_FS_IMAGE="yes" # Get arguments POSITIONAL_ARGS=() @@ -59,6 +60,10 @@ do CREATE_DUMP="yes" shift # past argument ;; + -n|--nofsimage) + CREATE_FS_IMAGE="" + shift # past argument + ;; -c|--config) USE_CONFIG_FILE="$2" shift # past argument @@ -154,7 +159,7 @@ fi # === Start building MicroPython firmware === # =========================================== -# === build mconf ======================= +# === build mconf ============================================== if [ ! -f "mconf" ] || [ ! -f "conf" ]; then echo "=====[ BUILD: compiling 'menuconfig' files" mkdir -p ../menuconfig/build @@ -170,15 +175,15 @@ if [ ! -f "mconf" ] || [ ! -f "conf" ]; then cd ../../k210-freertos if [ ! -f "mconf" ] || [ ! -f "conf" ]; then - echo "=====[ BUILD: ERROR, 'mconf' not compiled!" + echo "=====[ BUILD: ERROR, 'menuconfig' files not compiled!" exit 1 fi echo "=====[ BUILD: OK" sleep 1 fi -# ======================================= +# ============================================================== -# ==== Select confi file if requested ============================= +# ==== Select config file if requested ============================================ if [ "${USE_CONFIG_FILE}" != "" ]; then echo "=====[ BUILD: use '${USE_CONFIG_FILE}' as config file" if [ -f "${USE_CONFIG_FILE}" ]; then @@ -195,33 +200,45 @@ if [ "${USE_CONFIG_FILE}" != "" ]; then echo "=====[ BUILD: ERROR, '${USE_CONFIG_FILE}' not found!" fi fi -# ================================================================= +# ================================================================================= -# ==== Run menuconfig if requested or needed ============================== -if [ -f "mconf" ] && [ -f "conf" ]; then - if [ "${RUN_MENUCONFIG}" == "yes" ] || [ ! -f "mpy_support/k210_config.h" ]; then - echo "=====[ BUILD: Running 'menuconfig'" - rm -f mpy_support/k210_config.h > /dev/null 2>&1 - ./mconf Kconfig - if [ $? -ne 0 ]; then - echo "=====[ BUILD: error running 'mconf'" - exit 1 - fi - cp -f .config .config.old > /dev/null 2>&1 + +if [ "${RUN_MENUCONFIG}" == "yes" ]; then + # ==== Run menuconfig if requested or needed ============================== + echo "=====[ BUILD: Running 'menuconfig'" + rm -f mpy_support/k210_config.h > /dev/null 2>&1 + ./mconf Kconfig + if [ $? -ne 0 ]; then + echo "=====[ BUILD: error running 'mconf'" + exit 1 + fi + cp -f .config .config.old > /dev/null 2>&1 + ./conf --silentoldconfig mpy_support/k210_config.h Kconfig > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "=====[ BUILD: error creating 'k210.config.h'" + exit 1 + fi + echo "=====[ BUILD: Configuration files created." + echo "" + echo "=====[ BUILD: Run 'BUILD.sh' again to build the MicroPython firmware" + exit 0 + # ========================================================================= +else + # ==== Create 'k210.config.h' if not created ================================== + if [ ! -f "mpy_support/k210_config.h" ]; then + echo "=====[ BUILD: Creating 'k210.config.h'" + rm -f .config.old > /dev/null 2>&1 ./conf --silentoldconfig mpy_support/k210_config.h Kconfig > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "=====[ BUILD: error creating 'k210.config.h'" exit 1 fi echo "=====[ BUILD: Configuration files created." - echo "" - echo "=====[ BUILD: Run 'BUILD.sh' again to build the MicroPython firmware" - exit 0 fi + # ============================================================================= fi -# ========================================================================= -# === build mklfs ======================= +# === build mklfs & create image ========= if [ ! -f "../mklittlefs/mklfs" ]; then echo "=====[ BUILD: compiling 'mklfs'" make -C ../mklittlefs > /dev/null 2>&1 @@ -233,6 +250,22 @@ if [ ! -f "../mklittlefs/mklfs" ]; then fi sleep 1 fi + +rm -f ../mklittlefs/MicroPython_lfs.img > /dev/null 2>&1 +if [ "${CREATE_FS_IMAGE}" == "yes" ]; then +cd ../mklittlefs +if [ "${VERBOSE_BUILD}" == "" ]; then +./mklfs internalfs_image MicroPython_lfs.img > /dev/null 2>&1 +else +./mklfs internalfs_image MicroPython_lfs.img +fi +if [ $? -eq 0 ]; then +echo "=====[ BUILD: File system image created" +else +echo "=====[ BUILD: File system image NOT created" +fi +cd ../k210-freertos +fi # ======================================= # === build mpy-cross==================== @@ -257,11 +290,45 @@ fi # === Prepare the build === +MICROPY_OTA=$( cat mpy_support/k210_config.h | grep "CONFIG_MICROPY_USE_OTA" | cut -d' ' -s -f 3 ) +MICROPY_MBOOT_PIN=$( cat mpy_support/k210_config.h | grep "CONFIG_MICRO_PY_MBOOT_PIN" | cut -d' ' -s -f 3 ) +MICROPY_FW_SIZE_TYPE=$( cat mpy_support/k210_config.h | grep "CONFIG_FIRMWARE_SIZE_TYPE" | cut -d' ' -s -f 3 ) +if [ "${MICROPY_FW_SIZE_TYPE}" == "0" ]; then + MICROPY_FW_SIZE="(0x200000UL)" +elif [ "${MICROPY_FW_SIZE_TYPE}" == "1" ]; then + MICROPY_FW_SIZE="(0x280000UL)" +elif [ "${MICROPY_FW_SIZE_TYPE}" == "2" ]; then + MICROPY_FW_SIZE="(0x300000UL)" +else + MICROPY_FW_SIZE="(0x380000UL)" +fi + +if [ "${MICROPY_OTA}" != "" ]; then + echo "=====[ BUILD: compiling 'kboot'" + + echo "/*" > ../Kboot/src/bootloader_hi/include/config.h + echo " * Defined from MicroPython build" >> ../Kboot/src/bootloader_hi/include/config.h + echo " */" >> ../Kboot/src/bootloader_hi/include/config.h + echo "#define FIRMWARE_SIZE ${MICROPY_FW_SIZE}" >> ../Kboot/src/bootloader_hi/include/config.h + echo "#define BOOT_PIN ${MICROPY_MBOOT_PIN}" >> ../Kboot/src/bootloader_hi/include/config.h + echo "" >> ../Kboot/src/bootloader_hi/include/config.h + cd ../Kboot/build + ./BUILD.sh + if [ $? -eq 0 ]; then + echo "=====[ BUILD: ok." + else + cd ../../k210-freertos + echo "=====[ BUILD: ERROR!" + exit 1 + fi + cd ../../k210-freertos + cp -f ../Kboot/build/bootloader_??.bin . + cp -f ../Kboot/build/config.bin . +fi + MICROPY_VER=$( cat mpy_support/mpconfigport.h | grep "MICROPY_PY_LOBO_VERSION" | cut -d'"' -s -f 2 ) export MICROPY_VERSION="MicroPython_K210_LoBo v${MICRO_PI_VER}" -MICROPY_FW_SIZE_TYPE=$( cat mpy_support/k210_config.h | grep "CONFIG_FIRMWARE_SIZE_TYPE" | cut -d' ' -s -f 3 ) - MICROPY_FLASH_START=$( cat mpy_support/k210_config.h | grep "CONFIG_MICRO_PY_FLASHFS_START_ADDRESS" | cut -d' ' -s -f 3 ) FLASH_START_ADDRES=$(( ${MICROPY_FLASH_START} * 1024 * 1024 )) @@ -280,21 +347,19 @@ fi # -------------------------------------------------------- # Select the linker script based on firmware size selected # -------------------------------------------------------- -# LD_MODE="_kboot" -LD_MODE="" if [ "${MICROPY_FW_SIZE_TYPE}" == "0" ]; then echo "=====[ BUILD: 2 MB firmware" - cp -f platform/sdk/kendryte-freertos-sdk/lds/kendryte${LD_MODE}_2M.ld platform/sdk/kendryte-freertos-sdk/lds/kendryte.ld + cp -f platform/sdk/kendryte-freertos-sdk/lds/kendryte_2M.ld platform/sdk/kendryte-freertos-sdk/lds/kendryte.ld elif [ "${MICROPY_FW_SIZE_TYPE}" == "1" ]; then echo "=====[ BUILD: 2.5 MB firmware" - cp -f platform/sdk/kendryte-freertos-sdk/lds/kendryte${LD_MODE}_2_5M.ld platform/sdk/kendryte-freertos-sdk/lds/kendryte.ld + cp -f platform/sdk/kendryte-freertos-sdk/lds/kendryte_2_5M.ld platform/sdk/kendryte-freertos-sdk/lds/kendryte.ld elif [ "${MICROPY_FW_SIZE_TYPE}" == "2" ]; then echo "=====[ BUILD: 3 MB firmware" - cp -f platform/sdk/kendryte-freertos-sdk/lds/kendryte${LD_MODE}_3M.ld platform/sdk/kendryte-freertos-sdk/lds/kendryte.ld + cp -f platform/sdk/kendryte-freertos-sdk/lds/kendryte_3M.ld platform/sdk/kendryte-freertos-sdk/lds/kendryte.ld else echo "=====[ BUILD: 3.5 MB firmware" - cp -f platform/sdk/kendryte-freertos-sdk/lds/kendryte${LD_MODE}_3_5M.ld platform/sdk/kendryte-freertos-sdk/lds/kendryte.ld + cp -f platform/sdk/kendryte-freertos-sdk/lds/kendryte_3_5M.ld platform/sdk/kendryte-freertos-sdk/lds/kendryte.ld fi # -------------------------------------- @@ -350,20 +415,22 @@ FILESIZE=$(stat -s MicroPython.bin | cut -d' ' -s -f 1 | cut -d'=' -s -f 2) else FILESIZE=$(stat -c%s MicroPython.bin) fi -ALLIGNED_SIZE=$(( (((${FILESIZE} / 4096) * 4096)) + 8192 )) +ALIGNED_SIZE=$(( (((${FILESIZE} / 4096) * 4096)) + 8192 )) # Code in SRAM starts at 0x80000000, correct the address -END_ADDRESS=$(( ${ALLIGNED_SIZE} + 2147483648 )) -if [ "${LD_MODE}" == "_kboot" ]; then - # Code in SRAM starts at 0x80002000, correct the address - END_ADDRESS=$(( ${ALLIGNED_SIZE} + 2147483648 + 8192 )) -else - # Code in SRAM starts at 0x80000000, correct the address - END_ADDRESS=$(( ${ALLIGNED_SIZE} + 2147483648 )) -fi +END_ADDRESS=$(( ${ALIGNED_SIZE} + 2147483648 )) +# Code in SRAM starts at 0x80000000, correct the address +END_ADDRESS=$(( ${ALIGNED_SIZE} + 2147483648 )) mv MicroPython.bin MicroPython.bin.bkp ../kendryte-toolchain/bin/riscv64-unknown-elf-objcopy --output-format=binary --file-alignment 4096 --gap-fill 0xFF --pad-to ${END_ADDRESS} MicroPython MicroPython.bin +# Get real file size +if [ "${machine}" == "MacOS" ]; then +FILESIZE=$(stat -s MicroPython.bin | cut -d' ' -s -f 1 | cut -d'=' -s -f 2) +else +FILESIZE=$(stat -c%s MicroPython.bin) +fi + if [ "${CREATE_DUMP}" == "yes" ]; then echo "=====[ BUILD: Exporting objdump" ../kendryte-toolchain/bin/riscv64-unknown-elf-objdump -S --disassemble MicroPython > MicroPython.dump @@ -372,6 +439,54 @@ fi # ========================================= # === Create kfpkg package ================ # ========================================= + +if [ "${MICROPY_OTA}" != "" ]; then +echo "" +echo "=====[ BUILD: Creating 'MicroPython.kfpkg' (OTA)" +rm -f *.img > /dev/null 2>&1 +echo "{" > flash-list.json +echo " \"version\": \"0.1.0\"," >> flash-list.json +echo " \"files\": [">> flash-list.json +echo " {">> flash-list.json +echo " \"address\": 0,">> flash-list.json +echo " \"bin\": \"bootloader_lo.bin\",">> flash-list.json +echo " \"sha256Prefix\": true">> flash-list.json +echo " },">> flash-list.json +echo " {">> flash-list.json +echo " \"address\": 4096,">> flash-list.json +echo " \"bin\": \"bootloader_hi.bin\",">> flash-list.json +echo " \"sha256Prefix\": true">> flash-list.json +echo " },">> flash-list.json +echo " {">> flash-list.json +echo " \"address\": 16384,">> flash-list.json +echo " \"bin\": \"config.bin\",">> flash-list.json +echo " \"sha256Prefix\": false">> flash-list.json +echo " },">> flash-list.json +echo " {">> flash-list.json +echo " \"address\": 20480,">> flash-list.json +echo " \"bin\": \"config.bin\",">> flash-list.json +echo " \"sha256Prefix\": false">> flash-list.json +echo " },">> flash-list.json +echo " {">> flash-list.json +echo " \"address\": 65536,">> flash-list.json +echo " \"bin\": \"MicroPython.bin\",">> flash-list.json +echo " \"sha256Prefix\": true,">> flash-list.json +echo " \"swap\": false">> flash-list.json +if [ -f "${PWD}/../mklittlefs/MicroPython_lfs.img" ]; then +cp ${PWD}/../mklittlefs/MicroPython_lfs.img . +echo " },">> flash-list.json +echo " {">> flash-list.json +echo " \"address\": ${FLASH_START_ADDRES},">> flash-list.json +echo " \"bin\": \"MicroPython_lfs.img\",">> flash-list.json +echo " \"sha256Prefix\": false,">> flash-list.json +echo " \"swap\": false">> flash-list.json +echo " }">> flash-list.json +else +echo " }">> flash-list.json +fi +echo " ]">> flash-list.json +echo "}">> flash-list.json +else echo "" echo "=====[ BUILD: Creating 'MicroPython.kfpkg'" rm -f *.img > /dev/null 2>&1 @@ -390,24 +505,40 @@ echo " {">> flash-list.json echo " \"address\": ${FLASH_START_ADDRES},">> flash-list.json echo " \"bin\": \"MicroPython_lfs.img\",">> flash-list.json echo " \"sha256Prefix\": false,">> flash-list.json -echo " \"swap\": true">> flash-list.json +echo " \"swap\": false">> flash-list.json echo " }">> flash-list.json else echo " }">> flash-list.json fi echo " ]">> flash-list.json echo "}">> flash-list.json +fi -rm -f *.kfpkg > /dev/null 2>&1 -if [ -f MicroPython_lfs.img ]; then -zip MicroPython.kfpkg -9 flash-list.json MicroPython.bin MicroPython_lfs.img > /dev/null +if [ "${MICROPY_OTA}" != "" ]; then + rm -f *.kfpkg > /dev/null 2>&1 + if [ -f MicroPython_lfs.img ]; then + zip MicroPython.kfpkg -9 flash-list.json bootloader_lo.bin bootloader_hi.bin config.bin MicroPython.bin MicroPython_lfs.img > /dev/null + else + zip MicroPython.kfpkg -9 flash-list.json bootloader_lo.bin bootloader_hi.bin config.bin MicroPython.bin > /dev/null + fi + rm -f bootloader_??.bin + rm -f config.bin else -zip MicroPython.kfpkg -9 flash-list.json MicroPython.bin > /dev/null + rm -f *.kfpkg > /dev/null 2>&1 + if [ -f MicroPython_lfs.img ]; then + zip MicroPython.kfpkg -9 flash-list.json MicroPython.bin MicroPython_lfs.img > /dev/null + else + zip MicroPython.kfpkg -9 flash-list.json MicroPython.bin > /dev/null + fi fi if [ $? -eq 0 ]; then +if [ -f "${PWD}/../mklittlefs/MicroPython_lfs.img" ]; then echo "=====[ BUILD: kfpkg created" else +echo "=====[ BUILD: kfpkg created without FS image)" +fi +else echo "=====[ BUILD: ERROR creating kfpkg" exit 1 fi @@ -427,7 +558,7 @@ fi echo "=============================" echo "====== Build finished =======" echo " version: ${MICROPY_VER}" -echo " Firmware file size: ${ALLIGNED_SIZE}" +echo " Firmware file size: ${FILESIZE}" MICROPY_FILE_CRC32=$(crc32 MicroPython.bin 2> /dev/null) if [ $? -eq 0 ]; then echo " Firmware CRC32: ${MICROPY_FILE_CRC32}" diff --git a/k210-freertos/BUILD_ALL.sh b/k210-freertos/BUILD_ALL.sh index 2f612dc..6190ba9 100755 --- a/k210-freertos/BUILD_ALL.sh +++ b/k210-freertos/BUILD_ALL.sh @@ -2,50 +2,94 @@ cd k210-freertos > /dev/null 2>&1 +mkdir -p ../firmware/sqlite +mkdir -p ../firmware/twotasks +mkdir -p ../firmware/ota +cp -f ktool.py ../firmware +cp -f kflash.py ../firmware +cp -f MPyTerm.py ../firmware + +# ---------------------------------------------------- echo "=== BUILD default firmware ===" ./CLEAN.sh > /dev/null 2>&1 if [ $? -ne 0 ]; then +echo "=== ERROR ===" exit 1 fi ./BUILD.sh -c .config.default -j16 > /dev/null 2>&1 if [ $? -ne 0 ]; then +echo "=== ERROR ===" exit 1 fi cp -f MicroPython.bin ../firmware cp -f MicroPython.kfpkg ../firmware +# ---------------------------------------------------- -echo "=== BUILD sqlite firmware ===" +# ---------------------------------------------------- +echo "=== BUILD sqlite firmware ===" ./CLEAN.sh > /dev/null 2>&1 if [ $? -ne 0 ]; then +echo "=== ERROR ===" exit 1 fi ./BUILD.sh -c .config.sqlite -j16 > /dev/null 2>&1 if [ $? -ne 0 ]; then +echo "=== ERROR ===" exit 1 fi cp -f MicroPython.bin ../firmware/sqlite cp -f MicroPython.kfpkg ../firmware/sqlite +# ---------------------------------------------------- +# ---------------------------------------------------- echo "=== BUILD TwoTask firmware ===" ./CLEAN.sh > /dev/null 2>&1 if [ $? -ne 0 ]; then +echo "=== ERROR ===" exit 1 fi ./BUILD.sh -c .config.twotasks -j16 > /dev/null 2>&1 if [ $? -ne 0 ]; then +echo "=== ERROR ===" exit 1 fi cp -f MicroPython.bin ../firmware/twotasks cp -f MicroPython.kfpkg ../firmware/twotasks +# ---------------------------------------------------- + +# ---------------------------------------------------- +echo "=== BUILD OTA firmware ===" +./CLEAN.sh > /dev/null 2>&1 +if [ $? -ne 0 ]; then +echo "=== ERROR ===" +exit 1 +fi +./BUILD.sh -c .config.ota -j16 > /dev/null 2>&1 +if [ $? -ne 0 ]; then +echo "=== ERROR ===" +exit 1 +fi +cp -f MicroPython.bin ../firmware/ota +cp -f MicroPython.kfpkg ../firmware/ota +# ---------------------------------------------------- +# ---------------------------------------------------- +echo "" echo "=== Creating firmwares archive ===" cd ../firmware rm -f *.zip zip MicroPython_firmwares.zip -9 -r * cd ../k210-freertos +# ---------------------------------------------------- + +echo "=== Finished ===" + +./CLEAN.sh + +cp -f .config.default .config diff --git a/k210-freertos/CLEAN.sh b/k210-freertos/CLEAN.sh index 2aab053..eabd41a 100755 --- a/k210-freertos/CLEAN.sh +++ b/k210-freertos/CLEAN.sh @@ -2,6 +2,9 @@ cd k210-freertos > /dev/null 2>&1 +rm -Rf build/* > /dev/null 2>&1 +rm -Rf mpy_support/build/* > /dev/null 2>&1 + make -C ../micropython/mpy-cross clean -s V=1 make -C ../mklittlefs clean -s V=1 @@ -9,9 +12,7 @@ make -C ../mklittlefs clean -s V=1 make clean rm -f mpy_support/k210_config.h > /dev/null 2>&1 -cp -f .config.default .config -rm -Rf build/* > /dev/null 2>&1 rm -Rf tmp/* > /dev/null 2>&1 rm mconf > /dev/null 2>&1 rm conf > /dev/null 2>&1 diff --git a/k210-freertos/Kconfig b/k210-freertos/Kconfig index f6c6095..4699958 100644 --- a/k210-freertos/Kconfig +++ b/k210-freertos/Kconfig @@ -25,9 +25,9 @@ mainmenu "MicroPython for Kendryte K210" 3 MB - enough to build all MicroPython modules including sqlite3 3.5 MB - should be enough to build any firmware - If the insufficient size is selected, linker or runtime error will be reported + If the insufficient size is selected, linker or runtime error will be reported. - The rest of the K210 SRAM is used for FreeRTOS and MicroPython heaps + The rest of the K210 SRAM is used for FreeRTOS and MicroPython heaps. config FIRMWARE_SIZE_2_MB bool "2 MB" @@ -48,6 +48,25 @@ mainmenu "MicroPython for Kendryte K210" Is KPU is not used, 2 MB of SRAM is free to use and is used for FreeRTOS and MicroPython heaps. At the moment, KPU is not used by MicroPython, so this option can be disabled. + config MICROPY_USE_OTA + bool "Use OTA" + default n + help + If selected, the OTA feature is included in the firmware. + MicroPathon firmware can be upadte from various sources, for example from SDCard or internal file system + or from remote server over Internet (if Wifi or GSM is available to the system). + If selected, the OTA module will also be enabled. + + config MICRO_PY_MBOOT_PIN + int "Kboot pin" + range -1 47 + default -1 + depends on MICROPY_USE_OTA + help + Pin used to enter interactive mode and request the user to select which application to load + Any valid and not used K210 gpio can be used except gpio #16 (0 ~ 15 & 17 ~ 47) + KBoot pin can also be set from MicroPython 'ota' module. + config MICRO_PY_FREE_RTOS_RESERVED int "Default FreeRTOS heap size (KB)" default 896 if !MICROPY_K210_KPU_USED @@ -126,9 +145,10 @@ mainmenu "MicroPython for Kendryte K210" Default SPI Flash chip clock. On most board Flash chip will work without issues with the maximum clock of 83 MHZ. On some boards it will not work and the maximum clock must be reduced. + This sets Flash clock on boot, but it can be changed on runtime from MicroPython config MICROPY_BANK67_3V - bool "Pwr Bank 6&7 at 3.3V" + bool "Pwr Bank 6&7 at 3.3V (WARNING, see help)" default n help Set voltage for power bank 6 & 7 to 3.3V. @@ -190,6 +210,8 @@ mainmenu "MicroPython for Kendryte K210" default 4 help Start address of the Flash file system (in MB) + Set this addres higher than MicroPython firmware binary file size ! + If OTA is used, set this addres high enough to have a space for TWO firmwares ! config MICRO_PY_FLASHFS_SIZE int "Flash file system size (MB)" @@ -197,6 +219,7 @@ mainmenu "MicroPython for Kendryte K210" default 10 help Size of the Flash file system (in MB) + Take care that MICRO_PY_FLASHFS_START_ADDRESS+MICRO_PY_FLASHFS_SIZE is smaller or exual than the MICRO_PY_FLASH_SIZE config MICROPY_FILESYSTEM_TYPE int diff --git a/k210-freertos/changelog.txt b/k210-freertos/changelog.txt index ae42a3f..2c56850 100755 --- a/k210-freertos/changelog.txt +++ b/k210-freertos/changelog.txt @@ -1,4 +1,22 @@ +=================== +Date: Feb 06 2020 +=================== + +Micro Python core updated to the latest release 1.12 +Added initial support for OTA update +Updated 'uhashlib' module with better HW SHA256 support +Improved 'machine.flash_read' function +Fixed bugs in 'camera' module +Improved 'tft' module +Added initial support for OTA updates in 'requests' module +Improved SPI Flash driver +Disabled 'FIX_CACHE' option in FreeRTOS +Improved FreeRTOS SPI driver + + +=================== Date: Jan 28 2020 +=================== Large amount of changes and additions diff --git a/k210-freertos/kflash.py b/k210-freertos/kflash.py index d694ff1..9e9117c 100755 --- a/k210-freertos/kflash.py +++ b/k210-freertos/kflash.py @@ -1225,6 +1225,8 @@ def flash_firmware(self, firmware_bin, aes_key = None, address_offset = 0, sha25 else: KTool.log(INFO_MSG, 'Flashed {} B [{} chunks of {}B] ({:08X}~{:08X}) in {:.3f}s'.format( firmware_length, total_chunk, chunk_size, address_offset, curr_address+chunk_size-1, time.time()-time_start), BASH_TIPS['DEFAULT']) + if (sha256Prefix == True): + KTool.log(INFO_MSG, 'SHA256: {}'.format(binascii.hexlify(sha256_hash)), BASH_TIPS['DEFAULT']) # ============================== diff --git a/k210-freertos/ktool.py b/k210-freertos/ktool.py index d694ff1..9e9117c 100755 --- a/k210-freertos/ktool.py +++ b/k210-freertos/ktool.py @@ -1225,6 +1225,8 @@ def flash_firmware(self, firmware_bin, aes_key = None, address_offset = 0, sha25 else: KTool.log(INFO_MSG, 'Flashed {} B [{} chunks of {}B] ({:08X}~{:08X}) in {:.3f}s'.format( firmware_length, total_chunk, chunk_size, address_offset, curr_address+chunk_size-1, time.time()-time_start), BASH_TIPS['DEFAULT']) + if (sha256Prefix == True): + KTool.log(INFO_MSG, 'SHA256: {}'.format(binascii.hexlify(sha256_hash)), BASH_TIPS['DEFAULT']) # ============================== diff --git a/k210-freertos/main.c b/k210-freertos/main.c index 531639d..34c0a2f 100755 --- a/k210-freertos/main.c +++ b/k210-freertos/main.c @@ -391,6 +391,10 @@ static void mp_task_proc1(void *pvParameter) //======== int main() { + uint32_t *ld_mbootid = (uint32_t *)(MICROPY_SYS_RAMBUF_ADDR); + uint32_t *ld_address = (uint32_t *)(MICROPY_SYS_RAMBUF_ADDR+4); + uint32_t *ld_size = (uint32_t *)(MICROPY_SYS_RAMBUF_ADDR+8); + // ==== Basic initialization ==== // Setup clocks (default clocks set in 'entry_user.c') /* @@ -462,6 +466,21 @@ int main() if (cfg_loaded) LOGM(TAG, "Configuration loaded from flash"); else LOGM(TAG, "Default flash configuration set"); + #if MICROPY_PY_USE_OTA + if (*ld_mbootid == MICROPY_MBOOT_MAGIC_ID) { + if (*ld_address & 0x80000000) { + *ld_address &= 0x7fffffff; + LOGW(TAG, "OTA used: loaded default FW (addr=0x%08X, size=%u)", *ld_address, *ld_size); + } + else { + LOGM(TAG, "OTA used: loaded firmware from 0x%08X, size=%u", *ld_address, *ld_size); + } + } + else { + LOGM(TAG, "OTA used: cannot determine Mboot info"); + } + #endif + // ==== Initialize MicroPython HAL ==== mp_hal_init(); @@ -469,15 +488,16 @@ int main() mp_rtc_rtc0 = io_open("/dev/rtc0"); configASSERT(mp_rtc_rtc0); + // Set default datetime struct tm default_time = { .tm_sec = 0, .tm_min = 0, .tm_hour = 12, - .tm_mday = 4, - .tm_mon = 9 - 1, - .tm_year = 2019 - 1900, - .tm_wday = 4, + .tm_mday = 31, // day of the month (1~31) + .tm_mon = 1 - 1, // months since January (0~11) + .tm_year = 2020 - 1900, // years since 1900 + .tm_wday = 5, // days since Sunday (0~6) .tm_yday = -1, .tm_isdst = -1, }; diff --git a/k210-freertos/mpy_support/Makefile b/k210-freertos/mpy_support/Makefile index 2fcbc55..a6f5025 100644 --- a/k210-freertos/mpy_support/Makefile +++ b/k210-freertos/mpy_support/Makefile @@ -10,7 +10,8 @@ CUR_DIR_ADDR := $(shell pwd)/ LIB_NAME ?= mpy_support CROSS_COMPILE ?= OUTPUT_DIR := build/ -FROZEN_MPY_DIR ?= modules +#FROZEN_MPY_DIR ?= modules +FROZEN_MANIFEST ?= manifest.py MK_VALUE :="INC += "$(CUR_DIR_ADDR) MK_VALUE +="INC += "$(CUR_DIR_ADDR)"standard_lib/include/" MK_VALUE +="INC += "$(CUR_DIR_ADDR)"../platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/" diff --git a/k210-freertos/mpy_support/manifest.py b/k210-freertos/mpy_support/manifest.py new file mode 100644 index 0000000..066c6a4 --- /dev/null +++ b/k210-freertos/mpy_support/manifest.py @@ -0,0 +1 @@ +freeze('$(PORT_DIR)/modules') diff --git a/k210-freertos/mpy_support/modota.c b/k210-freertos/mpy_support/modota.c new file mode 100644 index 0000000..9d5d492 --- /dev/null +++ b/k210-freertos/mpy_support/modota.c @@ -0,0 +1,1031 @@ +/* + * This file is part of the MicroPython K210 project, https://github.com/loboris/MicroPython_K210_LoBo + * + * The MIT License (MIT) + * + * Copyright (c) 2020 LoBo (https://github.com/loboris) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + Boot configuration used by Kboot is stored in one SPI Flash sector (4KB) at fixed Flash address (0x00004000). + One backup configuration sector is also used for security reasons, + stored in one SPI Flash sector (4KB) at fixed Flash address (0x00005000). + + The configuration sector consists of 8 application entries occupying 32 bytes each. + After the last application entry the config flags entry is placed, one 32bit value. + + Configuration sector layout: + + | ---------------------------------------------- | + | From | To | Length | Comment | + | ---------------------------------------------- | + | 0x000 | 0x01F | 32 | application entry #0 | + | 0x020 | 0x03F | 32 | application entry #1 | + | 0x040 | 0x05F | 32 | application entry #2 | + | 0x060 | 0x07F | 32 | application entry #3 | + | 0x080 | 0x09F | 32 | application entry #4 | + | 0x0A0 | 0x0BF | 32 | application entry #5 | + | 0x0C0 | 0x0DF | 32 | application entry #6 | + | 0x0E0 | 0x0FF | 32 | application entry #7 | + | 0x100 | 0x103 | 4 | config flags | + | 0x104 | 0x11F | 4 | reserved | + | 0x120 | 0x11F | 4 | not used, user data | + | ---------------------------------------------- | + + The format of each _application entry_ in configuration sector is as follows: + + | ------------------------------------------------------------------------------------------------- | + | Offset | Length | Comment | + | ------------------------------------------------------------------------------------------------- | + | 0 | 4 | Configuration entry ID (bits 4-31) + entry flags (bits 0-4) | + | 4 | 4 | Application address in SPI Flash | + | 8 | 4 | Application size in SPI Flash. This is the size of the application's *.bin file | + | 12 | 4 | Application's CRC32 value (32bits) | + | 16 | 16 | Null terminated application name or description | + | ------------------------------------------------------------------------------------------------- | + + Notes: + Configuration entry ID must have a value of 0x5AA5D0C0 for entry to be recognized as valid. + Application addres must be in range 0x10000 ~ 0x800000 ( 64KB ~ 8MB ). + Application size must be in range 0x4000 ~ 0x300000 ( 16KB ~ 3MB ). + Application CRC32 value is used only if CRC32 flag is set. + + If config flags at offset 0x100 in configuration sector is set to configuration entry ID (0x5AA5D0C0), + interractive mode will be disabled, boot Pin will not be checked and nothing will be printed during the boot process. + + Configuration entry flags: + + | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Bit | Comment | + | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | 0 | 'Active' flag, if set the application will be loaded and executed. + | If multiple entries have active flag set, the first one will be loaded ad executed | + | 1 | 'CRC32' flag, if set the application's CRC32 value will be calculated and compared with the value in the configuration entry | + | 2 | 'AES256' flag, if set the application's AES256 hash value will be calculated and compared with the value stored in flash after the application code (SHA_HASH) | + | 3 | 'Size' flag, if set the application size specified in configuration entry must match the application size present in application's Flash block | + | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + + Warning: all 32-bit values in the configuration sector entries must be written in big-endian format. + */ + +/* + Each application stored in SPI Flash has the following format: + + | ----------------------------------------------------------------------------- | + | Byte offset | Size | Content | + | ----------------------------------------------------------------------------- | + | 0 | 1 | AES cipher flag, for use with **Kboot** must be `0` | + | 1 | 4 | Application code size | + | 5 | APP_SIZE | Application code | + | APP_SIZE + 5 | 32 | Application SHA256 hash | + | ----------------------------------------------------------------------------- | + + All applications flashed with **ktool.py** or **kflash.py** have such format. + */ + +#include "mpconfigport.h" + +#if MICROPY_PY_USE_OTA + +#include +#include +#include +#include "w25qxx.h" +#include "sha256_hard.h" +#include "spi.h" +#include "syslog.h" +#include "mphalport.h" + +#include "py/runtime.h" +#include "extmod/vfs.h" +#include "py/stream.h" + + +#define BOOT_CONFIG_ADDR 0x00004000 // main boot config sector in flash at 52K +#define BOOT_CONFIG_ITEMS 8 // number of handled config entries +#define BOOT_CONFIG_ITEM_SIZE 32 // size of config entry +#define BOOT_CONFIG_SECTOR_SIZE 4096 +#define BOOT_MAIN_SECTOR 1 +#define BOOT_BACKUP_SECTOR 2 + +#define MAGIC_ID 0x5AA5D0C0 +#define MAGIC_ID_FLAG 0xA55A60C0 +#define MAGIC_ID_MASK 0xFFFFFFF0 +#define CFG_APP_FLAG_ACTIVE 0x00000001 +#define CFG_APP_FLAG_CRC32 0x00000002 +#define CFG_APP_FLAG_SHA256 0x00000004 +#define CFG_APP_FLAG_SIZE 0x00000008 + +#define DEFAULT_APP_ADDRESS 0x00010000 +#define BOOT_ENTRY_NAME_LEN 16 + + +typedef struct _ota_entry_t { + uint32_t id_flags; + uint32_t address; + uint32_t size; + uint32_t crc32; + char name[BOOT_ENTRY_NAME_LEN]; +} __attribute__((packed, aligned(4))) ota_entry_t; + + +static uint8_t config_sector[BOOT_CONFIG_SECTOR_SIZE]; +static uint8_t config_loaded = 0; +static const char* TAG = "[OTA]"; + +/* +//------------------------------------------------- +static void _swap_endianess(uint8_t *buff, int len) +{ + uint32_t val_in, val; + for (int i=0; i> 24) & 0x000000ff; + val |= (val_in >> 8) & 0x0000ff00; + val |= (val_in << 8) & 0x00ff0000; + val |= (val_in << 24) & 0xff000000; + *((uint32_t *)(buff + (i*4))) = val; + } +} +*/ + +/* + * Get uint32_t value from Flash + * 8-bit Flash pointer is used, so the byte order must be swapped + * This is used when reading from not 4-byte aligned locations + * XIP must be already enabled! + */ +//----------------------------------------- +static uint32_t flash2uint32(uint32_t addr) +{ + uint32_t val = w25qxx_flash_ptr[addr]; + val += w25qxx_flash_ptr[addr+1] << 8; + val += w25qxx_flash_ptr[addr+2] << 16; + val += w25qxx_flash_ptr[addr+3] << 24; + return val; +} + +//-------------------------------------------- +static uint32_t swap_endian32(uint32_t val_in) +{ + uint32_t val = (val_in >> 24) & 0x000000ff; + val |= (val_in >> 8) & 0x0000ff00; + val |= (val_in << 8) & 0x00ff0000; + val |= (val_in << 24) & 0xff000000; + return val; +} + +// Swap endianness of 32-bit values in currently loaded config sector +//--------------------------------- +static void config_swap_endianess() +{ + // Swap endianness of all 32-bit entries + ota_entry_t *entry; + for (int i=0; i <= BOOT_CONFIG_ITEMS; i++) { + entry = (ota_entry_t *)(config_sector + (i*BOOT_CONFIG_ITEM_SIZE)); + entry->id_flags = swap_endian32(entry->id_flags); + entry->address = swap_endian32(entry->address); + entry->size = swap_endian32(entry->size); + entry->crc32 = swap_endian32(entry->crc32); + } +} + +// Read config sector into buffer +//------------------------------------------------ +static bool read_config(uint8_t n_conf, bool swap) +{ + if (config_loaded == n_conf) return true; + + config_loaded = 0; + enum w25qxx_status_t res; + bool curr_spi_check = w25qxx_spi_check; + w25qxx_spi_check = true; + res = w25qxx_read_data(BOOT_CONFIG_ADDR + ((n_conf-1) * BOOT_CONFIG_SECTOR_SIZE ), config_sector, BOOT_CONFIG_SECTOR_SIZE); + w25qxx_spi_check = curr_spi_check; + + if (res != W25QXX_OK) return false; + + if (swap) config_swap_endianess(); + + config_loaded = n_conf; + return true; +} + +// Backup main config sector to backup config sector +//------------------------------ +static bool backup_boot_sector() +{ + bool curr_spi_check = w25qxx_spi_check; + w25qxx_spi_check = true; + config_loaded = 0; // force load + if (!read_config(BOOT_MAIN_SECTOR, false)) { + w25qxx_spi_check = curr_spi_check; + LOGW(TAG, "Error reading main config sector"); + return false; + } + + enum w25qxx_status_t res; + res = w25qxx_write_data(BOOT_CONFIG_ADDR + BOOT_CONFIG_SECTOR_SIZE, config_sector, BOOT_CONFIG_SECTOR_SIZE); + config_swap_endianess(); + + if (res != W25QXX_OK) { + w25qxx_spi_check = curr_spi_check; + LOGW(TAG, "Error saving backup config sector"); + return false; + } + w25qxx_spi_check = curr_spi_check; + return true; +} + +// Restore main config sector from backup +//------------------------------- +static bool restore_boot_sector() +{ + bool curr_spi_check = w25qxx_spi_check; + w25qxx_spi_check = true; + config_loaded = 0; // force load + + if (!read_config(BOOT_BACKUP_SECTOR, false)) { + w25qxx_spi_check = curr_spi_check; + return false; + } + + enum w25qxx_status_t res; + res = w25qxx_write_data(BOOT_CONFIG_ADDR, config_sector, BOOT_CONFIG_SECTOR_SIZE); + if (res != W25QXX_OK) { + w25qxx_spi_check = curr_spi_check; + config_loaded = 0; + return false; + } + w25qxx_spi_check = curr_spi_check; + + config_swap_endianess(); + config_loaded = BOOT_MAIN_SECTOR; + + return true; +} + +// Write modified boot sector from buffer to Flash +//----------------------------- +static bool write_boot_sector() +{ + // Save modified boot sector + config_swap_endianess(); + config_loaded = 0; + bool curr_spi_check = w25qxx_spi_check; + w25qxx_spi_check = true; + enum w25qxx_status_t res = w25qxx_write_data(BOOT_CONFIG_ADDR, config_sector, BOOT_CONFIG_SECTOR_SIZE); + w25qxx_spi_check = curr_spi_check; + if (res != W25QXX_OK) { + LOGW(TAG, "Error writing config sector"); + // Try to restore backup sector + bool f = restore_boot_sector(); + if (f) { + LOGW(TAG, "Config sector restored"); + } + else { + LOGE(TAG, "Config sector NOT restored"); + } + return false; + } + return true; +} + +/* + * Calculate the firmware's SHA256 hash and get the stored SHA256 + * Complete firmware, including 5-byte prefix and 32-byte SHA hash, is expected at flash address + * The hash is 32 bytes long and written after the firmware's code + * The hash is calculated over 5-byte prefix and firmware's code ! + * by Ktool or other application + */ +//----------------------------------------------------------------------------- +static void calc_app_sha256(uint32_t address, uint8_t *hash, uint8_t *app_hash) +{ + w25qxx_enable_xip_mode(); + + memset(hash, 0, SHA256_HASH_LEN); + memset(app_hash, 0, SHA256_HASH_LEN); + + sha256_hard_context_t context; + uint8_t buffer[1024] = {0}; + int size = flash2uint32(address+1) + 5; + int sz; + uint32_t idx = 0; + uint32_t hash_offset = address + size; + + sha256_hard_init(&context, size); + + while (size > 0) { + sz = (size >= 1024) ? 1024 : size; + for (int n=0; n\r\n", hashhex); + for (int i=0; i> 1) ^ (0xEDB88320 & mask); + } + } + + w25qxx_disable_xip_mode(); + + return (~crc); +} + +// Check the firmware's CRC32 value +//-------------------------------------------------------- +static bool app_crc32(ota_entry_t *entry, uint32_t *crc32) +{ + *crc32 = calc_app_crc32(entry->address, entry->size); + if (*crc32 != entry->crc32) return false; + return true; +} + +// Get the size of the firmware at Flash address +//-------------------------------------------------- +static uint32_t get_fw_flash_size(uint32_t address) +{ + w25qxx_enable_xip_mode(); + uint32_t app_size = flash2uint32(address+1); + w25qxx_disable_xip_mode(); + return app_size; +} + +// Check the config sector entry +//---------------------------------------------------------- +static uint8_t check_entry(ota_entry_t *entry, char *status) +{ + uint8_t stat = 0; + if (status) status[0] = '\0'; + if ((entry->id_flags & MAGIC_ID_MASK) != MAGIC_ID) return false; + + uint32_t app_size = get_fw_flash_size(entry->address); + uint8_t flags = entry->id_flags & 0x0f; + + if (app_size != entry->size) { + if (status) strcat(status, "Size mismatch! "); + stat |= 1; + } + if (flags & CFG_APP_FLAG_SIZE) { + if (app_size != entry->size) { + stat |= 2; + return stat; + } + } + + if (flags & CFG_APP_FLAG_CRC32) { + uint32_t crc32; + if (!app_crc32(entry, &crc32)) { + if (status) strcat(status, "CRC32 Error "); + stat |= 4; + return stat; + } + } + if (flags & CFG_APP_FLAG_SHA256) { + if (!check_app_sha256(entry->address)) { + if (status) strcat(status, "SHA256 Error "); + stat |= 8; + return stat; + } + } + if (status) strcat(status, "Check OK "); + + return stat; +} + +// Copy the firmware from one Flash address to another +// Complete firmware, including 5-byte prefix and 32-byte SHA hash, is copied +// We assume that the source and destination address are aligned to 4K +//---------------------------------------------------------------------------------- +static bool firmware_copy(uint32_t src, uint32_t dest, uint32_t size, bool progress) +{ + uint8_t buffer[w25qxx_FLASH_SECTOR_SIZE]; + enum w25qxx_status_t res; + uint32_t idx=0, sz=0; + uint32_t total_size = size + 37; // add 5 byte prefix and 32 byte sha256 hash + float prog = 0.0; + // Align the size to sector size (4K) + if (total_size % w25qxx_FLASH_SECTOR_SIZE) { + total_size /= w25qxx_FLASH_SECTOR_SIZE; + total_size *= w25qxx_FLASH_SECTOR_SIZE; + total_size += w25qxx_FLASH_SECTOR_SIZE; + } + LOGD(TAG, "Firmware copy: total_size=%u (0x%08X, sectors=%u [%04X])", + total_size, total_size, total_size/w25qxx_FLASH_SECTOR_SIZE, total_size/w25qxx_FLASH_SECTOR_SIZE); + uint32_t copy_size = total_size; + + bool curr_spi_check = w25qxx_spi_check; + w25qxx_spi_check = true; + + while (total_size > 0) { + sz = (total_size > w25qxx_FLASH_SECTOR_SIZE) ? w25qxx_FLASH_SECTOR_SIZE : total_size; + res = w25qxx_read_data(src + idx, buffer, sz); + if (res != W25QXX_OK) break; + + res = w25qxx_write_data(dest + idx, buffer, sz); + if (res != W25QXX_OK) break; + + if (progress) { + prog = ((float)(copy_size - total_size) / (float)copy_size) * 100.0; + mp_printf(&mp_plat_print, "%.2f%% \r", prog); + } + + total_size -= sz; + idx += sz; + mp_hal_wdt_reset(); + } + w25qxx_spi_check = curr_spi_check; + if (progress) { + mp_printf(&mp_plat_print, "%s\r\n", (total_size == 0) ? "Finished" : "Failed "); + } + + if (total_size > 0) return false; + return true; +} + +// Write the firmware from file to Flash +// We assume that the destination address is aligned to 4K +//----------------------------------------------------------------------------------- +static bool firmware_write(mp_obj_t ffd, uint32_t dest, uint32_t size, bool progress) +{ + uint8_t buffer[w25qxx_FLASH_SECTOR_SIZE] = {0xFF}; + uint8_t fwhash[SHA256_HASH_LEN]; + sha256_hard_context_t context; + enum w25qxx_status_t res; + uint32_t idx=0, sz=0, rd; + uint32_t to_read = size; + float prog = 0.0; + bool first_sect = true; + bool f; + + LOGD(TAG, "Firmware write: file_size=%u (0x%08X, sectors=%u [%04X])", + size, size, size/w25qxx_FLASH_SECTOR_SIZE, size/w25qxx_FLASH_SECTOR_SIZE); + uint32_t copy_size = size; + + sha256_hard_init(&context, size+5); // init sha256 calculation + bool curr_spi_check = w25qxx_spi_check; + w25qxx_spi_check = true; + + while (to_read > 0) { + f = true; + if (first_sect) { + first_sect = false; + buffer[0] = 0; + *(uint32_t *)(buffer+1) = size; + sz = w25qxx_FLASH_SECTOR_SIZE - 5; + rd = mp_stream_posix_read((void *)ffd, buffer+5, sz); + f = (rd == sz); + to_read -= sz; + if (f) sha256_hard_update(&context, buffer, sz+5); + } + else { + sz = (to_read > w25qxx_FLASH_SECTOR_SIZE) ? w25qxx_FLASH_SECTOR_SIZE : to_read; + if (sz < w25qxx_FLASH_SECTOR_SIZE) memset(buffer, 0xFF, w25qxx_FLASH_SECTOR_SIZE); + rd = mp_stream_posix_read((void *)ffd, buffer, sz); + f = (rd == sz); + if (f) { + sha256_hard_update(&context, buffer, sz); + to_read -= sz; + if (to_read == 0) { + // Last data, add SHA256 hash + LOGD(TAG, "FW write: Last sector %u (%08X), size=%d", idx, idx, sz); + sha256_hard_final(&context, fwhash); + if ((sz + SHA256_HASH_LEN) > w25qxx_FLASH_SECTOR_SIZE) { + LOGE(TAG, "FW write: No space for SHA32 hash at %u (%d)", idx, w25qxx_FLASH_SECTOR_SIZE-sz-SHA256_HASH_LEN); + f = false; + break; + } + else memcpy(buffer+sz, fwhash, SHA256_HASH_LEN); + } + } + } + if (!f) { + LOGD(TAG, "FW write: read error at %u (%d <> %d)", idx, rd, sz); + break; + } + + // Write the full sector from 'buffer' to the Flash + res = w25qxx_write_data(dest + idx, buffer, w25qxx_FLASH_SECTOR_SIZE); + if (res != W25QXX_OK) { + LOGD(TAG, "FW write: write error at %u (size=%d)", idx, sz); + f = false; + break; + } + + if (progress) { + prog = ((float)(copy_size - to_read) / (float)copy_size) * 100.0; + mp_printf(&mp_plat_print, "%08X: %.2f%% \r", idx, prog); + } + + idx += w25qxx_FLASH_SECTOR_SIZE; // next sector + mp_hal_wdt_reset(); + } + + if (progress) { + if (f) mp_printf(&mp_plat_print, "%08X: 100%% \r\n", idx); + else mp_printf(&mp_plat_print, "\r\n"); + } + w25qxx_spi_check = curr_spi_check; + if (progress) { + mp_printf(&mp_plat_print, "%s\r\n", (f) ? "Finished" : "Failed"); + } + + return f; +} + +// Get the 1st active firmware from the main config sector +//---------------------------- +static int config_get_active() +{ + if (!read_config(BOOT_MAIN_SECTOR, true)) return -1; + + ota_entry_t *entry; + uint8_t stat, flags; + + for (int i=0; i < BOOT_CONFIG_ITEMS; i++) { + entry = (ota_entry_t *)(config_sector + (i*BOOT_CONFIG_ITEM_SIZE)); + if ((entry->id_flags & MAGIC_ID_MASK) == MAGIC_ID) { + flags = entry->id_flags & 0x0f; + if (flags & CFG_APP_FLAG_ACTIVE) { + stat = check_entry(entry, NULL); + if ((stat&0x7E) == 0) return i; + } + } + } + return -1; +} + +// Set the active main config sector entry +// Other entries, if active, are marked as inactive +//-------------------------------------------- +static bool config_set_active(uint8_t n_entry) +{ + if (!backup_boot_sector()) return false; + + ota_entry_t *entry; + uint8_t stat, flags; + bool f = false; + char status[32]; + + for (int i=0; i < BOOT_CONFIG_ITEMS; i++) { + entry = (ota_entry_t *)(config_sector + (i*BOOT_CONFIG_ITEM_SIZE)); + if ((entry->id_flags & MAGIC_ID_MASK) == MAGIC_ID) { + flags = entry->id_flags & 0x0f; + if (i == n_entry) { + if ((flags & CFG_APP_FLAG_ACTIVE) == 0) { + stat = check_entry(entry, status); + if ((stat&0x7E) != 0) { + if (strlen(status) > 0) status[strlen(status)-1] = '\0'; + LOGW(TAG, "Found config entry, but check failed [%s]", status); + break; + } + entry->id_flags |= CFG_APP_FLAG_ACTIVE; + f = true; + LOGD(TAG, "Config entry #%d set active", i); + break; + } + } + } + } + if (f) { + // mark other entries as not active + for (int i=0; i < BOOT_CONFIG_ITEMS; i++) { + entry = (ota_entry_t *)(config_sector + (i*BOOT_CONFIG_ITEM_SIZE)); + if ((entry->id_flags & MAGIC_ID_MASK) == MAGIC_ID) { + flags = entry->id_flags & 0x0f; + if ((i != n_entry) && (flags & CFG_APP_FLAG_ACTIVE)) { + entry->id_flags &= ~CFG_APP_FLAG_ACTIVE; + LOGD(TAG, "Config entry #%d set inactive", i); + } + } + } + // Save modified boot sector + return write_boot_sector(); + } + return false; +} + +// Enable or disable the Kboot interactive mode +//------------------------------------------------------ +static bool config_set_interactive(bool enable, int pin) +{ + if (!backup_boot_sector()) return false; + + uint32_t *mboot_flag = (uint32_t *)(config_sector + (BOOT_CONFIG_ITEMS*BOOT_CONFIG_ITEM_SIZE)); + + if (enable) { + if ((pin >= 0) && (pin < 48) && (pin != 16)) *mboot_flag = MAGIC_ID_FLAG | (pin & 0x3f); + else *mboot_flag = 0; + } + else *mboot_flag = MAGIC_ID; + + // Save modified boot sector + return write_boot_sector(); +} + +//-------------------------------------------------------------------------------------- +STATIC mp_obj_t mod_ota_list(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_print, ARG_sect }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_print, MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_sect, MP_ARG_INT, { .u_int = BOOT_MAIN_SECTOR } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t sect = args[ARG_sect].u_int & 3; + if ((sect != BOOT_MAIN_SECTOR) && (sect != BOOT_BACKUP_SECTOR)) { + mp_raise_ValueError("Wrong boot sector requested"); + } + + if (!read_config(sect, true)) { + mp_raise_msg(&mp_type_OSError, "Error reading config sector"); + } + + uint8_t flags; + ota_entry_t *entry; + char sflags[32]; + char status[32]; + uint8_t stat; + int n_entries = 0; + mp_obj_t entry_tuple[6]; + + for (int i=0; i < (BOOT_CONFIG_ITEMS-1); i++) { + entry = (ota_entry_t *)(config_sector + (i*BOOT_CONFIG_ITEM_SIZE)); + if ((entry->id_flags & MAGIC_ID_MASK) == MAGIC_ID) n_entries++; + } + mp_obj_t config_tuple[n_entries+1]; + n_entries = 0; + + if (args[ARG_print].u_bool) mp_printf(&mp_plat_print, "%s boot sector entries:\r\n", (sect == BOOT_MAIN_SECTOR) ? "Main" : "Backup"); + + for (int i=0; i < BOOT_CONFIG_ITEMS; i++) { + entry = (ota_entry_t *)(config_sector + (i*BOOT_CONFIG_ITEM_SIZE)); + if (i < (BOOT_CONFIG_ITEMS-1)) { + if ((entry->id_flags & MAGIC_ID_MASK) == MAGIC_ID) { + flags = entry->id_flags & 0x0f; + sflags[0] = '\0'; + if (flags & CFG_APP_FLAG_ACTIVE) strcat(sflags, "ACTIVE+"); + if (flags & CFG_APP_FLAG_CRC32) strcat(sflags, "CRC32+"); + if (flags & CFG_APP_FLAG_SHA256) strcat(sflags, "SHA256+"); + if (flags & CFG_APP_FLAG_SIZE) strcat(sflags, "SIZE+"); + if (strlen(sflags) > 0) sflags[strlen(sflags)-1] = '\0'; + stat = check_entry(entry, status); + if (strlen(status) > 0) status[strlen(status)-1] = '\0'; + + entry_tuple[0] = mp_obj_new_int(i); + entry_tuple[1] = mp_obj_new_int(flags); + entry_tuple[2] = mp_obj_new_int(entry->address); + entry_tuple[3] = mp_obj_new_int(entry->size); + entry_tuple[4] = mp_obj_new_str(entry->name, strlen(entry->name)); + entry_tuple[5] = mp_obj_new_int(stat); + + config_tuple[n_entries] = mp_obj_new_tuple(6, entry_tuple); + n_entries++; + if (args[ARG_print].u_bool) + mp_printf(&mp_plat_print, "%d: flags=[%s], addr=0x%08X, size=%u (%u), '%s', %s\r\n", + i, sflags, entry->address, entry->size, get_fw_flash_size(entry->address), entry->name, status); + } + } + else { + config_tuple[n_entries] = mp_obj_new_bool( ((entry->id_flags & MAGIC_ID_MASK) != MAGIC_ID) ); + if (args[ARG_print].u_bool) { + if ((entry->id_flags & MAGIC_ID_MASK) == MAGIC_ID) + mp_printf(&mp_plat_print, "Interactive mode disabled\r\n", entry->id_flags); + else + mp_printf(&mp_plat_print, "Interactive mode enabled\r\n", entry->id_flags); + } + } + } + return mp_obj_new_tuple(n_entries+1, config_tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ota_list_obj, 0, mod_ota_list); + +//--------------------------------------------------------------------------------------- +STATIC mp_obj_t mod_ota_clone(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_dest, ARG_address, ARG_active, ARG_progress }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_dest, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_active, MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_progress, MP_ARG_BOOL, { .u_bool = false } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Read the main config sector and backup it + if (!backup_boot_sector()) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error reading config sector")); + } + + int dest = args[ARG_dest].u_int; + if ((dest < 0) || (dest > (BOOT_CONFIG_ITEMS-1))) { + mp_raise_ValueError("Wrong dest index"); + } + uint32_t dest_address = (uint32_t)args[ARG_address].u_int & 0xFFFFF000; + uint32_t src_address, src_end_address, src_size, dest_end_address; + ota_entry_t *active_entry = NULL; + + ota_entry_t default_entry = {0}; + default_entry.id_flags = (uint32_t)(MAGIC_ID + CFG_APP_FLAG_ACTIVE + CFG_APP_FLAG_SHA256); + default_entry.address = DEFAULT_APP_ADDRESS; + default_entry.size = get_fw_flash_size(DEFAULT_APP_ADDRESS); + sprintf(default_entry.name, "MicroPython"); + + int src = config_get_active(); + if (src >= 0) active_entry = (ota_entry_t *)(config_sector + (src*BOOT_CONFIG_ITEM_SIZE)); + else active_entry = &default_entry; + src_address = active_entry->address; + src_size = get_fw_flash_size(active_entry->address); + src_end_address = ((src_address + src_size) & 0xFFFFF000) + 0x1000; + dest_end_address = ((dest_address + src_size) & 0xFFFFF000) + 0x1000; + + if (src == dest) { + mp_raise_ValueError("Source and destination equal!"); + } + // Check if valid destination Flash area is selected + if ( ((dest_address >= MICRO_PY_FLASHFS_START_ADDRESS) || (dest_end_address >= MICRO_PY_FLASHFS_START_ADDRESS)) || + ((dest_address < DEFAULT_APP_ADDRESS) || (dest_end_address < DEFAULT_APP_ADDRESS)) || + ((dest_address >= src_address) && (dest_address <= src_end_address)) || + ((dest_end_address >= src_address) && (dest_end_address <= src_end_address)) ) { + mp_raise_ValueError("Wrong destination address!"); + } + + // Copy firmware + LOGD(TAG, "Firmware copy: %d -> %d: 0x%08X -> 0x%08X, size=%u", src, dest, src_address, dest_address, src_size); + if (firmware_copy(src_address, dest_address, src_size, args[ARG_progress].u_bool)) { + // Set the destination entry data + ota_entry_t *dest_entry = (ota_entry_t *)(config_sector + (dest*BOOT_CONFIG_ITEM_SIZE)); + dest_entry->id_flags = (uint32_t)(MAGIC_ID + CFG_APP_FLAG_SHA256 + ((args[ARG_active].u_bool) ? CFG_APP_FLAG_ACTIVE : 0)); + dest_entry->address = dest_address; + dest_entry->size = src_size; + dest_entry->crc32 = 0; + memcpy(dest_entry->name, active_entry->name, BOOT_ENTRY_NAME_LEN); + LOGD(TAG, "Adding boot entry #%d: %08X, %08X, %u", dest, dest_entry->id_flags, dest_entry->address, dest_entry->size); + + if (!write_boot_sector()) { + mp_raise_msg(&mp_type_OSError, "Error saving config sector."); + } + LOGD(TAG, "Boot entry #%d saved.", dest); + } + else { + mp_raise_msg(&mp_type_OSError, "Error while copying firmware."); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ota_clone_obj, 2, mod_ota_clone); + +//--------------------------------------------------------------------------------------------- +STATIC mp_obj_t mod_ota_fw_fromfile(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_dest, ARG_address, ARG_file, ARG_name, ARG_active, ARG_progress }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_dest, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_name, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_active, MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_progress, MP_ARG_BOOL, { .u_bool = false } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Read the main config sector and backup it + if (!backup_boot_sector()) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error reading config sector")); + } + + uint32_t active_address, active_end_address, active_size, dest_end_address; + ota_entry_t *active_entry = NULL; + uint32_t dest_address = (uint32_t)args[ARG_address].u_int & 0xFFFFF000; + int dest = args[ARG_dest].u_int; + if ((dest < 0) || (dest > (BOOT_CONFIG_ITEMS-1))) { + mp_raise_ValueError("Wrong dest index"); + } + + char entry_name[BOOT_ENTRY_NAME_LEN] = {'\0'}; + char *fname = NULL; + mp_obj_t dest_file = mp_const_none; + int fsize = 0; + + if (mp_obj_is_str(args[ARG_name].u_obj)) { + char *ename = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + snprintf(entry_name, BOOT_ENTRY_NAME_LEN, "%s", ename); + } + else sprintf(entry_name, "MicroPython"); + + if (mp_obj_is_str(args[ARG_file].u_obj)) { + fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + mp_obj_t fargs[2]; + fargs[0] = mp_obj_new_str(fname, strlen(fname)); + fargs[1] = mp_obj_new_str("rb", 2); + dest_file = mp_vfs_open(2, fargs, (mp_map_t*)&mp_const_empty_map); + if (!dest_file) { + mp_raise_msg(&mp_type_OSError, "Error opening firmware file"); + } + // Get file size + fsize = mp_stream_posix_lseek((void *)dest_file, 0, SEEK_END); + int at_start = mp_stream_posix_lseek((void *)dest_file, 0, SEEK_SET); + if ((fsize < (512*1024)) || (at_start != 0)) { + mp_stream_close(dest_file); + mp_raise_ValueError("Wrong file size"); + } + } + else { + mp_raise_ValueError("File name not provided"); + } + + // Get current firmware information + ota_entry_t default_entry = {0}; + default_entry.id_flags = (uint32_t)(MAGIC_ID + CFG_APP_FLAG_ACTIVE + CFG_APP_FLAG_SHA256); + default_entry.address = DEFAULT_APP_ADDRESS; + default_entry.size = get_fw_flash_size(DEFAULT_APP_ADDRESS); + sprintf(default_entry.name, "MicroPython"); + + int src = config_get_active(); + if (src == dest) { + mp_raise_ValueError("Source and destination equal!"); + } + + if (src >= 0) active_entry = (ota_entry_t *)(config_sector + (src*BOOT_CONFIG_ITEM_SIZE)); + else active_entry = &default_entry; + active_address = active_entry->address; + active_size = get_fw_flash_size(active_entry->address); + active_end_address = ((active_address + active_size) & 0xFFFFF000) + 0x1000; + + dest_end_address = ((dest_address + fsize) & 0xFFFFF000) + 0x1000; + + // Check if valid destination Flash area is selected + if ( ((dest_address >= MICRO_PY_FLASHFS_START_ADDRESS) || (dest_end_address >= MICRO_PY_FLASHFS_START_ADDRESS)) || + ((dest_address < DEFAULT_APP_ADDRESS) || (dest_end_address < DEFAULT_APP_ADDRESS)) || + ((dest_address >= active_address) && (dest_address <= active_end_address)) || + ((dest_end_address >= active_address) && (dest_end_address <= active_end_address)) ) { + mp_raise_ValueError("Wrong destination address!"); + } + + // Write the firmware from file + LOGD(TAG, "Firmware write: %d: 0x%08X, size=%u", dest, dest_address, fsize); + if (firmware_write(dest_file, dest_address, fsize, args[ARG_progress].u_bool)) { + mp_stream_close(dest_file); + // Set the destination entry data + ota_entry_t *dest_entry = (ota_entry_t *)(config_sector + (dest*BOOT_CONFIG_ITEM_SIZE)); + dest_entry->id_flags = (uint32_t)(MAGIC_ID + CFG_APP_FLAG_SHA256 + ((args[ARG_active].u_bool) ? CFG_APP_FLAG_ACTIVE : 0)); + dest_entry->address = dest_address; + dest_entry->size = fsize; + dest_entry->crc32 = 0; + memcpy(dest_entry->name, entry_name, BOOT_ENTRY_NAME_LEN); + LOGD(TAG, "Adding boot entry #%d: %08X, %08X, %u", dest, dest_entry->id_flags, dest_entry->address, dest_entry->size); + + // Save modified boot sector + if (!write_boot_sector()) { + mp_raise_msg(&mp_type_OSError, "Error saving config sector."); + } + LOGD(TAG, "Boot entry #%d saved.", dest); + } + else { + mp_stream_close(dest_file); + mp_raise_msg(&mp_type_OSError, "Error while writing firmware."); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ota_fw_fromfile_obj, 3, mod_ota_fw_fromfile); + +//-------------------------------------------------- +STATIC mp_obj_t mod_ota_setactive(mp_obj_t entry_in) +{ + int entry = mp_obj_get_int(entry_in); + if ((entry < 0) || (entry > (BOOT_CONFIG_ITEMS-1))) { + mp_raise_ValueError("Wrong config entry index"); + } + + bool res = config_set_active(entry); + return mp_obj_new_bool(res); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ota_setactive_obj, mod_ota_setactive); + +//------------------------------------------------------------------------- +STATIC mp_obj_t mod_ota_setInteractive(size_t n_args, const mp_obj_t *args) +{ + bool enable = mp_obj_is_true(args[0]); + int pin = -1; + if (n_args > 1) { + pin = mp_obj_get_int(args[1]); + if ((pin < 0) || (pin >= 48) || (pin == 16)) { + mp_raise_ValueError("Allowed boot pins: 0 ~ 15 & 17 ~47"); + } + } + + bool res = config_set_interactive(enable, pin); + return mp_obj_new_bool(res); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_ota_setInteractive_obj, 1, 2, mod_ota_setInteractive); + +//=========================================================== +STATIC const mp_map_elem_t ota_module_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ota) }, + + { MP_ROM_QSTR(MP_QSTR_list), MP_ROM_PTR(&mod_ota_list_obj) }, + { MP_ROM_QSTR(MP_QSTR_clone), MP_ROM_PTR(&mod_ota_clone_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_ota_fw_fromfile_obj) }, + { MP_ROM_QSTR(MP_QSTR_setActive), MP_ROM_PTR(&mod_ota_setactive_obj) }, + { MP_ROM_QSTR(MP_QSTR_setInteractive), MP_ROM_PTR(&mod_ota_setInteractive_obj) }, +}; + +//=========================== +STATIC MP_DEFINE_CONST_DICT ( + ota_module_globals, + ota_module_globals_table +); + +const mp_obj_module_t ota_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&ota_module_globals, +}; + +#endif // MICROPY_PY_USE_OTA diff --git a/k210-freertos/mpy_support/moduhashlib_k210.c b/k210-freertos/mpy_support/moduhashlib_k210.c index 9146414..e50269f 100644 --- a/k210-freertos/mpy_support/moduhashlib_k210.c +++ b/k210-freertos/mpy_support/moduhashlib_k210.c @@ -39,8 +39,7 @@ #endif #if MICROPY_PY_UHASHLIB_SHA256_K210 -#include -#include +#include "sha256_hard.h" #endif typedef struct _mp_obj_hash_t { @@ -48,7 +47,7 @@ typedef struct _mp_obj_hash_t { char state[0]; } mp_obj_hash_t; - +// ================================================================================================================== #if MICROPY_PY_UHASHLIB_SHA1_K210 STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg); @@ -105,63 +104,65 @@ STATIC const mp_obj_type_t uhashlib_sha1_type = { .locals_dict = (void*)&uhashlib_sha1_locals_dict, }; #endif +// ================================================================================================================== + +// ================================================================================================================== #if MICROPY_PY_UHASHLIB_SHA256_K210 STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg); -STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + +//------------------------------------------------------------------------------------------------------------------- +STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) +{ mp_arg_check_num(n_args, n_kw, 0, 1, false); - mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(sha256_context)); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(sha256_hard_context_t)); o->base.type = type; - sha256_starts((sha256_context*)o->state, 0); + sha256_hard_init((sha256_hard_context_t*)o->state, 0); if (n_args == 1) { uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]); } return MP_OBJ_FROM_PTR(o); } -STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { +//-------------------------------------------------------------------- +STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) +{ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - sha256_update((sha256_context*)self->state, bufinfo.buf, bufinfo.len); + sha256_hard_update((sha256_hard_context_t*)self->state, bufinfo.buf, bufinfo.len); return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update); -STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { +//----------------------------------------------------- +STATIC mp_obj_t uhashlib_sha256_final(mp_obj_t self_in) +{ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); vstr_t vstr; vstr_init_len(&vstr, 32); - sha256_finish((sha256_context*)self->state, (byte*)vstr.buf); - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); -} - -STATIC mp_obj_t uhashlib_sha256(mp_obj_t arg) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - vstr_t vstr; - vstr_init_len(&vstr, 32); - sha256(bufinfo.buf, bufinfo.len, (byte*)vstr.buf, 0); + sha256_hard_final((sha256_hard_context_t*)self->state, (byte*)vstr.buf); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_final_obj, uhashlib_sha256_final); -STATIC mp_obj_t uhashlib_sha256_hard(mp_obj_t arg) { +//------------------------------------------- +STATIC mp_obj_t uhashlib_sha256(mp_obj_t arg) +{ mp_buffer_info_t bufinfo; mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); vstr_t vstr; vstr_init_len(&vstr, 32); - sha256_hard_calculate(bufinfo.buf, bufinfo.len, (byte*)vstr.buf); + sha256_hard_calc(bufinfo.buf, bufinfo.len, (byte*)vstr.buf); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } - -STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest); STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_obj, uhashlib_sha256); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_hard_obj, uhashlib_sha256_hard); STATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha256_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha256_digest_obj) }, + { MP_ROM_QSTR(MP_QSTR_final), MP_ROM_PTR(&uhashlib_sha256_final_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha256_final_obj) }, }; STATIC MP_DEFINE_CONST_DICT(uhashlib_sha256_locals_dict, uhashlib_sha256_locals_dict_table); @@ -172,7 +173,10 @@ STATIC const mp_obj_type_t uhashlib_sha256_type = { .locals_dict = (void*)&uhashlib_sha256_locals_dict, }; #endif +// ================================================================================================================== + +// ================================================================================================================== #if MICROPY_PY_UHASHLIB_MD5_K210 STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg); @@ -229,7 +233,9 @@ STATIC const mp_obj_type_t uhashlib_md5_type = { .locals_dict = (void*)&uhashlib_md5_locals_dict, }; #endif // MICROPY_PY_UHASHLIB_MD5_K210 +// ================================================================================================================== +//=================================================================== STATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uhashlib) }, #if MICROPY_PY_UHASHLIB_SHA1_K210 @@ -239,7 +245,6 @@ STATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = { #if MICROPY_PY_UHASHLIB_SHA256_K210 { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&uhashlib_sha256_type) }, { MP_ROM_QSTR(MP_QSTR_get_sha256), MP_ROM_PTR(&uhashlib_sha256_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_sha256_hard), MP_ROM_PTR(&uhashlib_sha256_hard_obj) }, #endif #if MICROPY_PY_UHASHLIB_MD5_K210 { MP_ROM_QSTR(MP_QSTR_md5), MP_ROM_PTR(&uhashlib_md5_type) }, @@ -249,6 +254,7 @@ STATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = { STATIC MP_DEFINE_CONST_DICT(mp_module_uhashlib_globals, mp_module_uhashlib_globals_table); +//------------------------------------------ const mp_obj_module_t mp_module_uhashlib = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_uhashlib_globals, diff --git a/k210-freertos/mpy_support/mpconfigport.h b/k210-freertos/mpy_support/mpconfigport.h index 9618634..3934ef0 100755 --- a/k210-freertos/mpy_support/mpconfigport.h +++ b/k210-freertos/mpy_support/mpconfigport.h @@ -42,7 +42,8 @@ extern uint32_t _ram_end; // Set this to 0 for normal build! -#define MICROPY_DEBUG_BUILD (1) +#define MICROPY_DEBUG_BUILD (1) +#define MICROPY_MBOOT_MAGIC_ID 0x5AA5D0C0 // =========================================== // Options to control how MicroPython is built @@ -52,8 +53,8 @@ extern uint32_t _ram_end; #define MICROPY_HW_MCU_NAME CONFIG_MICROPY_HW_MCU_NAME #define MICROPY_PY_SYS_PLATFORM "K210/FreeRTOS" -#define MICROPY_PY_LOBO_VERSION "1.11.12" -#define MICROPY_PY_LOBO_VERSION_NUM (0x011112) +#define MICROPY_PY_LOBO_VERSION "1.12.01" +#define MICROPY_PY_LOBO_VERSION_NUM (0x011201) #ifdef CONFIG_MICROPY_PY_USE_LOG_COLORS #define MICROPY_PY_USE_LOG_COLORS (1) @@ -61,6 +62,12 @@ extern uint32_t _ram_end; #define MICROPY_PY_USE_LOG_COLORS (0) #endif +#ifdef CONFIG_MICROPY_USE_OTA +#define MICROPY_PY_USE_OTA (1) +#else +#define MICROPY_PY_USE_OTA (0) +#endif + /* Several basic configurations can be selected for build: ------------------------------------------------------- @@ -113,16 +120,16 @@ extern uint32_t _ram_end; #endif -/* ==== K210 Memory usage ========================================================================================= +/* ==== K210 Memory usage ====================================================================================== * K210 has 8 MB of SRAM - * 2.5 MB or 3 MB is reserved for firmware, static and global variables and heap used by various internal functions + * 2MB ~ 3.5MB is reserved for firmware, static and global variables and heap used by various internal functions * If the KPU is used, last 2 MB are reserved for its use - * The remaining (5.5 MB, 5 MB or 3 MB) is used for FreeRTOS heap + * The remaining (4.5MB ~ 6MB or 2.5MB ~ 4MB) is used for FreeRTOS heap * - MicroPython heap is allocated from FreeRTOS heap * - thread's (task's) stacks and all buffers are allocated from FreeRTOS heap * - If two MicroPython instances are configured, the available heap space is divided between them, * default values are: 5/8 for 1st MicroPython instance and 3/8 for the 2nd - * ================================================================================================================ + * ============================================================================================================= */ #define K210_SRAM_START_ADDRESS (0x80000000UL) @@ -170,7 +177,7 @@ extern uint32_t _ram_end; * ====================================================================== * When KPU memory is used to expand the FreeRTOS heap * some variables (on task stack or on FreeRTOS heap) may be placed - * at SRAM address above 0x8060000 ! + * at SRAM address above 0x80600000 ! * Those wariabled CAN'T be used in DMA transfers involving peripherals ! * ====================================================================== */ @@ -751,6 +758,13 @@ extern const struct _mp_obj_module_t mp_test_module; #define BUILTIN_MODULE_TEST #endif +#if MICROPY_PY_USE_OTA +extern const struct _mp_obj_module_t ota_module; +#define BUILTIN_MODULE_OTA { MP_OBJ_NEW_QSTR(MP_QSTR_ota), (mp_obj_t)&ota_module }, +#else +#define BUILTIN_MODULE_OTA +#endif + #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&utime_module }, \ @@ -772,6 +786,7 @@ extern const struct _mp_obj_module_t mp_test_module; BUILTIN_MODULE_UTIMEQ_K210 \ BUILTIN_MODULE_SQLITE \ BUILTIN_MODULE_TEST \ + BUILTIN_MODULE_OTA \ /* #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ diff --git a/k210-freertos/mpy_support/mphalport.c b/k210-freertos/mpy_support/mphalport.c index ef37695..f6d96a9 100755 --- a/k210-freertos/mpy_support/mphalport.c +++ b/k210-freertos/mpy_support/mphalport.c @@ -35,6 +35,7 @@ #include "py/obj.h" #include "py/mpstate.h" #include "py/mphal.h" +#include "py/stream.h" #include "extmod/misc.h" #include "lib/utils/pyexec.h" #include "mphalport.h" @@ -74,6 +75,14 @@ uint64_t sys_us_counter = 0; uint32_t system_status = 0; +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { + uintptr_t ret = 0; + if ((poll_flags & MP_STREAM_POLL_RD) && stdin_ringbuf.iget != stdin_ringbuf.iput) { + ret |= MP_STREAM_POLL_RD; + } + return ret; +} + // =================================== // === MicroPython ticks functions === // =================================== diff --git a/k210-freertos/mpy_support/sha256_hard.c b/k210-freertos/mpy_support/sha256_hard.c new file mode 100644 index 0000000..9a94d27 --- /dev/null +++ b/k210-freertos/mpy_support/sha256_hard.c @@ -0,0 +1,125 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "sha256_hard.h" +#include "sysctl.h" +#include "encoding.h" +#include "mphalport.h" + +#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) + + +volatile sha256_hard_t *const sha256_hard = (volatile sha256_hard_t *)SHA256_BASE_ADDR; +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, 0x00, 0x00}; + +static inline uint64_t byteswap64(uint64_t x) +{ + uint32_t a = (uint32_t)(x >> 32); + uint32_t b = (uint32_t)x; + return ((uint64_t)BYTESWAP(b) << 32) | (uint64_t)BYTESWAP(a); +} + +void sha256_hard_init(sha256_hard_context_t *context, size_t input_len) +{ + //sysctl_clock_enable(SYSCTL_CLOCK_SHA); + sysctl->clk_en_cent.apb0_clk_en = 1; + sysctl->clk_en_peri.sha_clk_en = 1; + //sysctl_reset(SYSCTL_RESET_SHA); + sysctl->peri_reset.sha_reset = 1; + mp_hal_usdelay(10); + sysctl->peri_reset.sha_reset = 0; + + sha256_hard->sha_num_reg.sha_data_cnt = (uint32_t)((input_len + SHA256_BLOCK_LEN + 8) / SHA256_BLOCK_LEN); + sha256_hard->sha_function_reg_1.dma_en = 0x0; + sha256_hard->sha_function_reg_0.sha_endian = SHA256_BIG_ENDIAN; + sha256_hard->sha_function_reg_0.sha_en = ENABLE_SHA; + context->total_len = 0L; + context->buffer_len = 0L; +} + +void sha256_hard_update(sha256_hard_context_t *context, const void *input, size_t input_len) +{ + const uint8_t *data = input; + size_t buffer_bytes_left; + size_t bytes_to_copy; + uint32_t i; + + while(input_len) + { + buffer_bytes_left = SHA256_BLOCK_LEN - context->buffer_len; + bytes_to_copy = buffer_bytes_left; + if(bytes_to_copy > input_len) + bytes_to_copy = input_len; + memcpy(&context->buffer.bytes[context->buffer_len], data, bytes_to_copy); + context->total_len += bytes_to_copy * 8L; + context->buffer_len += bytes_to_copy; + data += bytes_to_copy; + input_len -= bytes_to_copy; + if(context->buffer_len == SHA256_BLOCK_LEN) + { + for(i = 0; i < 16; i++) + { + while(sha256_hard->sha_function_reg_1.fifo_in_full) + ; + sha256_hard->sha_data_in1 = context->buffer.words[i]; + } + context->buffer_len = 0L; + } + } +} + +void sha256_hard_final(sha256_hard_context_t *context, uint8_t *output) +{ + size_t bytes_to_pad; + size_t length_pad; + uint32_t i; + + bytes_to_pad = 120L - context->buffer_len; + if(bytes_to_pad > 64L) + bytes_to_pad -= 64L; + length_pad = BYTESWAP64(context->total_len); + sha256_hard_update(context, padding, bytes_to_pad); + sha256_hard_update(context, &length_pad, 8L); + while(!(sha256_hard->sha_function_reg_0.sha_en)) + ; + if(output) + { + for(i = 0; i < SHA256_HASH_WORDS; i++) + { + *((uint32_t *)output) = sha256_hard->sha_result[SHA256_HASH_WORDS - i - 1]; + output += 4; + } + } +} + +void sha256_hard_calc(const uint8_t *input, size_t input_len, uint8_t *output) +{ + sha256_hard_context_t sha; + sha256_hard_init(&sha, input_len); + sha256_hard_update(&sha, input, input_len); + sha256_hard_final(&sha, output); +} diff --git a/k210-freertos/mpy_support/sha256_hard.h b/k210-freertos/mpy_support/sha256_hard.h new file mode 100644 index 0000000..3989480 --- /dev/null +++ b/k210-freertos/mpy_support/sha256_hard.h @@ -0,0 +1,127 @@ +/* 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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ENABLE_SHA (0x1) +#define SHA256_BIG_ENDIAN (0x1) + +#define SHA256_HASH_LEN 32 +#define SHA256_HASH_WORDS 8 +#define SHA256_BLOCK_LEN 64L + +typedef struct _sha_num_reg +{ + /* The total amount of data calculated by SHA256 is set by this register, and the smallest unit is 512bit. */ + uint32_t sha_data_cnt : 16; + /* currently calculated block number. 512bit=1block*/ + uint32_t sha_data_num : 16; +} __attribute__((packed, aligned(4))) sha_num_reg_t; + +typedef struct _sha_function_reg_0 +{ + /* write:SHA256 enable register. read:Calculation completed flag */ + uint32_t sha_en : 1; + uint32_t reserved00 : 7; + /* SHA256 calculation overflow flag */ + uint32_t sha_overflow : 1; + uint32_t reserved01 : 7; + /* Endian setting; b'0:little endian b'1:big endian */ + uint32_t sha_endian : 1; + uint32_t reserved02 : 15; +} __attribute__((packed, aligned(4))) sha_function_reg_0_t; + +typedef struct _sha_function_reg_1 +{ + /* Sha and DMA handshake signals enable.b'1:enable;b'0:disable */ + uint32_t dma_en : 1; + uint32_t reserved10 : 7; + /* b'1:sha256 fifo is full; b'0:not full */ + uint32_t fifo_in_full : 1; + uint32_t reserved11 : 23; +} __attribute__((packed, aligned(4))) sha_function_reg_1_t; + +typedef struct _sha256_hard +{ + /* Calculated sha256 return value. */ + uint32_t sha_result[8]; + /* SHA256 input data from this register. */ + uint32_t sha_data_in1; + uint32_t reselved0; + sha_num_reg_t sha_num_reg; + sha_function_reg_0_t sha_function_reg_0; + uint32_t reserved1; + sha_function_reg_1_t sha_function_reg_1; +} __attribute__((packed, aligned(4))) sha256_hard_t; + +typedef struct _sha256_hard_context +{ + size_t total_len; + size_t buffer_len; + union + { + uint32_t words[16]; + uint8_t bytes[64]; + } buffer; +} sha256_hard_context_t; + +/** + * @brief Init SHA256 calculation context + * + * @param[in] context SHA256 context object + * + */ +void sha256_hard_init(sha256_hard_context_t *context, size_t input_len); + +/** + * @brief Called repeatedly with chunks of the message to be hashed + * + * @param[in] context SHA256 context object + * @param[in] data_buf data chunk to be hashed + * @param[in] buf_len length of data chunk + * + */ +void sha256_hard_update(sha256_hard_context_t *context, const void *input, size_t input_len); + +/** + * @brief Finish SHA256 hash process, output the result. + * + * @param[in] context SHA256 context object + * @param[out] output The buffer where SHA256 hash will be output + * + */ +void sha256_hard_final(sha256_hard_context_t *context, uint8_t *output); + +/** + * @brief Simple SHA256 hash once. + * + * @param[in] data Data will be hashed + * @param[in] data_len Data length + * @param[out] output Output buffer + * + */ +void sha256_hard_calc(const uint8_t *input, size_t input_len, uint8_t *output); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/display/moddisplay_tft.c b/k210-freertos/mpy_support/standard_lib/display/moddisplay_tft.c index 812a8d5..d1f10f3 100644 --- a/k210-freertos/mpy_support/standard_lib/display/moddisplay_tft.c +++ b/k210-freertos/mpy_support/standard_lib/display/moddisplay_tft.c @@ -200,7 +200,7 @@ STATIC mp_obj_t display_tft_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_ self->buff_obj0 = mp_obj_new_frame_buffer((active_dstate->_width * active_dstate->_height * 2) + 8); if (self->buff_obj0 == mp_const_none) active_dstate->use_frame_buffer = false; else if (args[ARG_useFB].u_int > 1) { - self->buff_obj0 = mp_obj_new_frame_buffer((active_dstate->_width * active_dstate->_height * 2) + 8); + self->buff_obj1 = mp_obj_new_frame_buffer((active_dstate->_width * active_dstate->_height * 2) + 8); } mp_obj_array_t *fbuf = (mp_obj_array_t *)self->buff_obj0; active_dstate->_tft_frame_buffer = fbuf->items; diff --git a/k210-freertos/mpy_support/standard_lib/display/tftspi.c b/k210-freertos/mpy_support/standard_lib/display/tftspi.c index acaf0ca..bbde946 100644 --- a/k210-freertos/mpy_support/standard_lib/display/tftspi.c +++ b/k210-freertos/mpy_support/standard_lib/display/tftspi.c @@ -114,7 +114,7 @@ static int tft_dc_gpionum = 0; static mp_fpioa_cfg_item_t disp_pin_func[DISP_NUM_FUNC]; static uint32_t tft_spi_speed = SPI_DEFAULT_SPEED; -//static const char TAG[] = "[TFTSPI]"; +static const char TAG[] = "[TFTSPI]"; static uint8_t invertrot = 1; // ==== Functions ===================== @@ -250,16 +250,18 @@ static void tft_write_byte(uint8_t* data_buf, uint32_t length) io_write(spi_dfs8, (const uint8_t *)(data_buf), length); } +// send to display from buffer of 16-bit color values //------------------------------------------------------------- -static void tft_write_half(uint16_t* data_buf, uint32_t length) +static void tft_write_rgb565(uint16_t* data_buf, uint32_t length) { set_dcx_data(); io_write(spi_dfs16, (const uint8_t *)(data_buf), length * 2); } /* -//------------------------------------------------------------- -static void tft_write_word(uint32_t* data_buf, uint32_t length) +// send to display from buffer of 32-bit values +//-------------------------------------------------------------- +static void tft_write_32bit(uint32_t* data_buf, uint32_t length) { set_dcx_data(); io_write(spi_dfs32, (const uint8_t *)data_buf, length * 4); @@ -354,7 +356,7 @@ void drawPixel(int16_t x, int16_t y, color_t color) disp_spi_transfer_addrwin(x, x, y, y); - tft_write_half(&color, 1); + tft_write_rgb565(&color, 1); } // Write 'len' color data to TFT 'window' (x1,y2),(x2,y2) @@ -405,18 +407,20 @@ void send_data(int x1, int y1, int x2, int y2, uint32_t len, color_t *buf) disp_spi_transfer_addrwin(x1, x2, y1, y2); // Send color buffer - tft_write_half(buf, len); + tft_write_rgb565(buf, len); } // Write color data to TFT framebuffer from given buffer //================================================================================== void send_data_scale(int x1, int y1, int width, int height, color_t *buf, int scale) { - if (!active_dstate->use_frame_buffer) return; + //if (!active_dstate->use_frame_buffer) return; if ((x1==0) && (y1==0) && (width == active_dstate->_width) && (height == active_dstate->_height) && (scale <= 1)) { - memcpy(active_dstate->tft_frame_buffer, buf, width*height*2); - return; + if (active_dstate->use_frame_buffer) { + memcpy(active_dstate->tft_frame_buffer, buf, width*height*2); + return; + } } int x, y; // input buffer coordinates @@ -436,7 +440,11 @@ void send_data_scale(int x1, int y1, int width, int height, color_t *buf, int sc tx = (x/xyscale) + x1; // display column if (tx < 0) continue; if (tx >= active_dstate->_width) break; - active_dstate->tft_frame_buffer[(ty * active_dstate->_width) + tx] = buf[(y * width) + x]; + if (active_dstate->use_frame_buffer) active_dstate->tft_frame_buffer[(ty * active_dstate->_width) + tx] = buf[(y * width) + x]; + else if (active_dstate->tft_active_mode == TFT_MODE_TFT) { + drawPixel(x, y, buf[(y * width) + x]); + mp_hal_wdt_reset(); + } } } } @@ -446,17 +454,11 @@ void send_data_scale(int x1, int y1, int width, int height, color_t *buf, int sc void send_frame_buffer() { if ((active_dstate->use_frame_buffer) && active_dstate->tft_frame_buffer) { - /* + LOGV(TAG, "Send frame buffer at %p", active_dstate->tft_frame_buffer); // ** Send address window ** disp_spi_transfer_addrwin(0, active_dstate->_width-1, 0, active_dstate->_height-1); // Send color buffer - tft_write_half(active_dstate->tft_frame_buffer, 0xFC00); - */ - // ** Send address window ** - disp_spi_transfer_addrwin(0, active_dstate->_width-1, 0, active_dstate->_height/2-1); - tft_write_half(active_dstate->tft_frame_buffer, active_dstate->_width*active_dstate->_height/2); - disp_spi_transfer_addrwin(0, active_dstate->_width-1, active_dstate->_height/2, active_dstate->_height-1); - tft_write_half(active_dstate->tft_frame_buffer+(active_dstate->_width*active_dstate->_height/2), active_dstate->_width*active_dstate->_height/2); + tft_write_rgb565(active_dstate->tft_frame_buffer, active_dstate->_width*active_dstate->_height); } } diff --git a/k210-freertos/mpy_support/standard_lib/machine/camera/dvp_camera.c b/k210-freertos/mpy_support/standard_lib/machine/camera/dvp_camera.c index 1cedfed..9e53c19 100644 --- a/k210-freertos/mpy_support/standard_lib/machine/camera/dvp_camera.c +++ b/k210-freertos/mpy_support/standard_lib/machine/camera/dvp_camera.c @@ -151,9 +151,6 @@ bool dvp_init(sensor_t *sensor) } } - // Set DVP clock - sensor->xclk = (uint32_t)dvp_xclk_set_clock_rate(sensor->dvp_handle, CAMERA_XCLK_FREQUENCY); - LOGD(TAG, "DVP clock: %u", sensor->xclk); // Disable DVP output for now dvp_set_output_enable(sensor->dvp_handle, DATA_FOR_AI, false); dvp_set_output_enable(sensor->dvp_handle, DATA_FOR_DISPLAY, false); @@ -184,14 +181,19 @@ bool dvp_init(sensor_t *sensor) } break; case SENSORTYPE_AUTO: + LOGD(TAG, "Camera auto detect"); if (ov2640_init(sensor) != 0) { if (ov5640_init(sensor) != 0) { dvp_deinit(sensor); return false; } + LOGD(TAG, "OV5640"); sensor->sensor_type = SENSORTYPE_OV5640; } - else sensor->sensor_type = SENSORTYPE_OV2640; + else { + LOGD(TAG, "OV2640"); + sensor->sensor_type = SENSORTYPE_OV2640; + } break; default: LOGE(TAG, "Unsupported camera type"); @@ -200,6 +202,13 @@ bool dvp_init(sensor_t *sensor) } } + // Set DVP clock + if (sensor->sensor_type == SENSORTYPE_OV5640) + sensor->xclk = (uint32_t)dvp_xclk_set_clock_rate(sensor->dvp_handle, CAMERA_XCLK_FREQUENCY); + else + sensor->xclk = (uint32_t)dvp_xclk_set_clock_rate(sensor->dvp_handle, CAMERA_XCLK_FREQUENCY1); + LOGD(TAG, "DVP clock: %u", sensor->xclk); + // === Reset and initialize the camera === sensor->reset(); if (dvp_check_framesize(sensor->sensor_type, sensor->framesize) != 0) { diff --git a/k210-freertos/mpy_support/standard_lib/machine/camera/dvp_camera.h b/k210-freertos/mpy_support/standard_lib/machine/camera/dvp_camera.h index db1bda5..96f3eaa 100644 --- a/k210-freertos/mpy_support/standard_lib/machine/camera/dvp_camera.h +++ b/k210-freertos/mpy_support/standard_lib/machine/camera/dvp_camera.h @@ -33,7 +33,8 @@ #define DVP_JPEG_BUF_AISRAM_SIZE 0x200000 #define DVP_JPEG_BUF_SIZE (512*1024) -#define CAMERA_XCLK_FREQUENCY (26000000) +#define CAMERA_XCLK_FREQUENCY (16000000) +#define CAMERA_XCLK_FREQUENCY1 (26000000) enum _data_for { diff --git a/k210-freertos/mpy_support/standard_lib/machine/camera/mod_camera.c b/k210-freertos/mpy_support/standard_lib/machine/camera/mod_camera.c index c2f3d81..4e93414 100644 --- a/k210-freertos/mpy_support/standard_lib/machine/camera/mod_camera.c +++ b/k210-freertos/mpy_support/standard_lib/machine/camera/mod_camera.c @@ -41,8 +41,9 @@ #include "dvp_camera.h" #include "../display/moddisplay.h" -#define USE_DEBUG_PIN 1 -#define DEBUG_PIN_NUM 18 +// Only for debug +#define USE_DEBUG_PIN 0 +#define DEBUG_PIN_NUM 13 #define DEST_BUFFER 0 #define DEST_TFT 1 @@ -461,9 +462,10 @@ STATIC void mod_camera_print(const mp_print_t *print, mp_obj_t self_in, mp_print { mod_camera_obj_t *self = MP_OBJ_TO_PTR(self_in); if (camera_is_init) { - mp_printf(print, "Camera(%s) %dx%d, buffer: %s%u, status: %s", + mp_printf(print, "Camera(%s) %dx%d, xclk: %u MHz, buffer: %s%u, status: %s", (self->sensor.sensor_type == SENSORTYPE_OV2640) ? "OV2640" : "OV5640", dvp_cam_resolution[self->sensor.framesize][0], dvp_cam_resolution[self->sensor.framesize][1], + self->sensor.xclk, (self->preview_task) ? "2*" : "", self->sensor.gram_size+8, (self->preview_task) ? "Preview" : "Capture"); } @@ -774,6 +776,7 @@ STATIC mp_obj_t mod_camera_capture(mp_uint_t n_args, const mp_obj_t *pos_args, m LOGD(TAG, "Frame (%ux%u) captured (%lu ms), processing", width, height, mp_hal_ticks_ms()-tstart); if (mp_obj_is_str(args[ARG_dest].u_obj)) { + LOGD(TAG, "Capture to file"); dest = DEST_FILE; // === capture to file === mp_obj_t fargs[2]; @@ -789,10 +792,12 @@ STATIC mp_obj_t mod_camera_capture(mp_uint_t n_args, const mp_obj_t *pos_args, m } else if (args[ARG_dest].u_obj != mp_const_none) { int dst = mp_obj_get_int(args[ARG_dest].u_obj); + LOGD(TAG, "Capture to %d", dst); if (dst == DEST_BUFFER) dest = DEST_BUFFER; } if (dest == DEST_TFT) { + LOGD(TAG, "Capture to display"); if (active_dstate->tft_frame_buffer == NULL) { _restore_mode_size(self, orig_size, buf_size); mp_raise_msg(&mp_type_OSError, "TFT frame buffer not initialized"); @@ -802,6 +807,7 @@ STATIC mp_obj_t mod_camera_capture(mp_uint_t n_args, const mp_obj_t *pos_args, m if (self->sensor.pixformat == PIXFORMAT_JPEG) { // === Process JPEG data === + LOGD(TAG, "Process JPEG"); // jpeg data are written to frame buffer as 32-bit values with swapped endianness! mp_obj_array_t *gram0; gram0 = (mp_obj_array_t *)self->buff_obj0; @@ -864,23 +870,27 @@ STATIC mp_obj_t mod_camera_capture(mp_uint_t n_args, const mp_obj_t *pos_args, m } else { // === Process RGB565 data === + LOGD(TAG, "Process RGB565"); // Captured data have swapped even and odd pixels, fix it // (Data are written to buffer as 32-bit values) swap_pixels((uint16_t *)frame_buffer, width*height); if (dest == DEST_BUFFER) { + LOGD(TAG, "Save to buffer"); *(uint16_t *)(frame_buffer-8) = width; *(uint16_t *)(frame_buffer-6) = height; memcpy(frame_buffer-4, "rawB", 4); result = mp_obj_new_str_copy(&mp_type_bytes, (const byte*)(frame_buffer-8), (width*height*2)+8); } else if (dest == DEST_TFT) { + LOGD(TAG, "Show on display"); send_data_scale(0, 0, width, height, (color_t *)frame_buffer, 0); tft_setup((uint8_t)(args[ARG_time].u_int & 3)); send_frame_buffer(); } else if ((dest == DEST_FILE) && (ffd != mp_const_none)) { + LOGD(TAG, "Save to file"); *(uint16_t *)(frame_buffer-8) = width; *(uint16_t *)(frame_buffer-6) = height; memcpy(frame_buffer-4, "rawB", 4); @@ -894,6 +904,7 @@ STATIC mp_obj_t mod_camera_capture(mp_uint_t n_args, const mp_obj_t *pos_args, m else if (ffd != mp_const_none) mp_stream_close(ffd); } + LOGD(TAG, "Processed"); _restore_mode_size(self, orig_size, buf_size); return result; } diff --git a/k210-freertos/mpy_support/standard_lib/machine/modmachine.c b/k210-freertos/mpy_support/standard_lib/machine/modmachine.c index c7810b3..d7e99f8 100755 --- a/k210-freertos/mpy_support/standard_lib/machine/modmachine.c +++ b/k210-freertos/mpy_support/standard_lib/machine/modmachine.c @@ -239,7 +239,8 @@ mp_obj_t exec_code_from_str(const char *strdata) mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, strdata, strlen(strdata), 0); qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); + // mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); //MPy 1.11 + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true); mp_call_function_0(module_fun); nlr_pop(); } else { @@ -779,48 +780,75 @@ STATIC mp_obj_t mod_machine_reset_reason() } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_machine_reset_reason_obj, mod_machine_reset_reason); -//------------------------------------------------------------------------- -STATIC mp_obj_t mod_machine_flash_read(size_t n_args, const mp_obj_t *args) +//----------------------------------------------------------------------------------------------- +STATIC mp_obj_t mod_machine_flash_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - uint32_t addr = mp_obj_get_int(args[0]); - bool to_buff = false; - bool swap = false; - if (n_args > 1) to_buff = mp_obj_is_true(args[1]); - if (n_args > 2) swap = mp_obj_is_true(args[2]); - uint8_t buf[512] = {0}; + enum { ARG_address, ARG_size, ARG_tobuff, ARG_onlytime, ARG_noswap, ARG_noxip }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_size, MP_ARG_INT, { .u_int = 512 } }, + { MP_QSTR_tobuff, MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_onlytime, MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_noswap, MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_noxip, MP_ARG_BOOL, { .u_bool = false } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint32_t size = ((args[ARG_size].u_int >= 32) && (args[ARG_size].u_int <= 4096)) ? args[ARG_size].u_int : 512; + size &= 0xFFFFFFFC; + uint32_t addr = ((args[ARG_address].u_int >= 0) && (args[ARG_address].u_int <= (MICRO_PY_FLASH_SIZE-size))) ? args[ARG_address].u_int : 0; + bool to_buff = args[ARG_tobuff].u_bool; + uint64_t start_time=0, end_time=0; + + uint8_t buf[size]; enum w25qxx_status_t res; - res = w25qxx_read_data(addr, buf, 512); + start_time = mp_hal_ticks_us(); + if (args[ARG_noxip].u_bool) { + if (args[ARG_noswap].u_bool) w25qxx_swap_dat = false; + res = w25qxx_read_data(addr, buf, size); + end_time = mp_hal_ticks_us(); + if (args[ARG_noswap].u_bool) w25qxx_swap_dat = true; + } + else { + res = w25qxx_enable_xip_mode(); + } + if (res == W25QXX_OK) { - if (swap) { - uint8_t buf4[4]; - for (int k=0; k<512; k+=4) { - buf4[0] = buf[k+0]; - buf4[1] = buf[k+1]; - buf4[2] = buf[k+2]; - buf4[3] = buf[k+3]; - buf[k+0] = buf4[3]; - buf[k+1] = buf4[2]; - buf[k+2] = buf4[1]; - buf[k+3] = buf4[0]; + if (!args[ARG_noxip].u_bool) { + for (int n=0; n 1) to_buff = mp_obj_is_true(args[1]); + if (n_args > 2) to_buff = mp_obj_is_true(args[2]); if (addr > (K210_TOTAL_SRAM_SIZE - size)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "reading %lu bytes from address %08x outside of RAM area", size, addr)); } @@ -837,7 +865,7 @@ STATIC mp_obj_t mod_machine_read_sram(size_t n_args, const mp_obj_t *args) if (to_buff) { return mp_obj_new_str_copy(&mp_type_bytes, buff, size); } - for (int k=0; k<512; k++) { + for (int k=0; k 90000000)) { - mp_raise_ValueError("Allowed flash speeds: 20~90 MHzz"); + mp_raise_ValueError("Allowed flash speeds: 20~90 MHz"); } flash_speed = w25qxx_init(flash_spi, SPI_FF_QUAD, flash_speed); } diff --git a/k210-freertos/mpy_support/standard_lib/network/modrequests.c b/k210-freertos/mpy_support/standard_lib/network/modrequests.c index 9edf814..bd4a7a8 100644 --- a/k210-freertos/mpy_support/standard_lib/network/modrequests.c +++ b/k210-freertos/mpy_support/standard_lib/network/modrequests.c @@ -37,6 +37,7 @@ #include "http_client.h" #include "transport.h" +#include "w25qxx.h" #include "py/obj.h" #include "py/runtime.h" @@ -55,6 +56,8 @@ static const char *TAG_EVENT = "[REQUESTS EVENT]"; static char *rqheader = NULL; static char *rqbody = NULL; static mp_obj_t rqbody_file = mp_const_none; +static uint32_t flash_address = 0; +static uint32_t flash_length = 0; static int rqheader_ptr = 0; static int rqbody_len = DEFAULT_RQBODY_LEN; static int rqbody_ptr = 0; @@ -133,6 +136,19 @@ static int _http_event_handler(esp_http_client_event_t *evt) rqbody_ptr += evt->data_len; } } + else if (flash_address > 0) { + if ((rqbody_ptr+evt->data_len) <= flash_length) { + enum w25qxx_status_t res = w25qxx_write_data(flash_address+rqbody_ptr, evt->data, evt->data_len); + if (res != W25QXX_OK) { + rqbody_ok = false; + if (transport_debug) LOGE(TAG_EVENT, "Download: Error writing to Flash"); + } + else { + if (transport_debug) LOGI(TAG_EVENT, "Write data to Flash: rqptr=%d + %d", flash_address+rqbody_ptr, evt->data_len); + rqbody_ptr += evt->data_len; + } + } + } else { if (transport_debug) LOGI(TAG_EVENT, "Write data to body buffer: rqptr=%d/%d", rqbody_ptr, rqbody_len); if (rqbody != NULL) { @@ -631,6 +647,10 @@ static mp_obj_t request(int method, bool multipart, mp_obj_t post_data_in, char sprintf(rqbody, "Saved to file '%s', size=%d", tofile, rqbody_ptr); tuple[2] = mp_obj_new_str(rqbody, strlen(rqbody)); } + else if (flash_address > 0) { + sprintf(rqbody, "Saved to Flash at '%08X', size=%d, expected=%u", flash_address, rqbody_ptr, flash_length); + tuple[2] = mp_obj_new_str(rqbody, strlen(rqbody)); + } else if ((rqbody) && (rqbody_ptr)) tuple[2] = mp_obj_new_bytes((const byte*)rqbody, rqbody_ptr); else tuple[2] = mp_const_none; @@ -693,11 +713,12 @@ void get_certificate(mp_obj_t cert, char *cert_pem_buf) STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { //network_checkConnection(); - enum { ARG_url, ARG_file, ARG_bufsize }; + enum { ARG_url, ARG_file, ARG_bufsize, ARG_flashsize }; const mp_arg_t allowed_args[] = { { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, { MP_QSTR_file, MP_ARG_OBJ, { .u_obj = mp_const_none } }, { MP_QSTR_bufsize, MP_ARG_INT, { .u_int = 1536 } }, + { MP_QSTR_flashsize, MP_ARG_INT, { .u_int = 0 } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -705,13 +726,31 @@ STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t * char *url = NULL; char *fname = NULL; + flash_address = 0; + flash_length = 0; url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); - if (mp_obj_is_str(args[ARG_file].u_obj)) { + #if MICROPY_PY_USE_OTA + if (mp_obj_is_int(args[ARG_file].u_obj)) { + // GET to Flash, used for OTA download + flash_address = mp_obj_get_int(args[ARG_file].u_obj); + flash_length = mp_obj_get_int(args[ARG_flashsize].u_obj); + // Check address and size + } + else if (mp_obj_is_str(args[ARG_file].u_obj)) { + // GET to file + fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + } + #else + if (mp_obj_is_int(args[ARG_file].u_obj)) { + mp_raise_ValueError("Save to Flash not supported if OTA not enabled"); + } + else if (mp_obj_is_str(args[ARG_file].u_obj)) { // GET to file fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); } + #endif mp_obj_t res = request(HTTP_METHOD_GET, false, NULL, url, fname, args[ARG_bufsize].u_int); @@ -735,6 +774,8 @@ STATIC mp_obj_t requests_HEAD(size_t n_args, const mp_obj_t *pos_args, mp_map_t url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); + flash_address = 0; + flash_length = 0; mp_obj_t res = request(HTTP_METHOD_HEAD, false, NULL, url, NULL, 1536); return res; @@ -769,6 +810,8 @@ STATIC mp_obj_t requests_POST(size_t n_args, const mp_obj_t *pos_args, mp_map_t fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); } + flash_address = 0; + flash_length = 0; mp_obj_t res = request(HTTP_METHOD_POST, args[ARG_multipart].u_bool, args[ARG_params].u_obj, url, fname, args[ARG_bufsize].u_int); return res; @@ -792,6 +835,8 @@ STATIC mp_obj_t requests_PUT(size_t n_args, const mp_obj_t *pos_args, mp_map_t * url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); + flash_address = 0; + flash_length = 0; mp_obj_t res = request(HTTP_METHOD_PUT, false, args[ARG_data].u_obj, url, NULL, 1536); return res; @@ -815,6 +860,8 @@ STATIC mp_obj_t requests_PATCH(size_t n_args, const mp_obj_t *pos_args, mp_map_t url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); + flash_address = 0; + flash_length = 0; mp_obj_t res = request(HTTP_METHOD_PATCH, false, args[ARG_data].u_obj, url, NULL, 1536); return res; @@ -838,6 +885,8 @@ STATIC mp_obj_t requests_DELETE(size_t n_args, const mp_obj_t *pos_args, mp_map_ url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); + flash_address = 0; + flash_length = 0; mp_obj_t res = request(HTTP_METHOD_DELETE, false, args[ARG_data].u_obj, url, NULL, 1536); return res; diff --git a/k210-freertos/platform/drivers/include/w25qxx.h b/k210-freertos/platform/drivers/include/w25qxx.h index 7f8edf6..f8d2193 100644 --- a/k210-freertos/platform/drivers/include/w25qxx.h +++ b/k210-freertos/platform/drivers/include/w25qxx.h @@ -51,9 +51,12 @@ #define CHIP_SELECT 1 #define WAIT_CYCLE 8 -#define FRAME_LENGTH 8 +// Setting the FRAME_LENGTH(_XXXX) to 32 causes every 32-bit value +// to have bytes SWAPPED (0x11223344 -> 0x44332211) +#define FRAME_LENGTH_SINGLE 8 #define FRAME_LENGTH_DUAL 32 #define FRAME_LENGTH_QUAD 32 + #define INSTRUCTION_LENGTH 8 #define ADDRESS_LENGTH 24 @@ -120,6 +123,10 @@ extern uint32_t w25qxx_flash_speed; extern uint32_t w25qxx_actual_speed; extern uint8_t work_trans_mode; extern uint8_t __attribute__((aligned(8))) swap_buf[w25qxx_FLASH_SECTOR_SIZE]; +extern uint8_t *w25qxx_flash_ptr; +extern uint16_t *w25qxx_flash_ptr16; +extern uint32_t *w25qxx_flash_ptr32; +extern bool w25qxx_swap_dat; void w25qxx_clear_counters(); void w25qxx_get_counters(uint32_t *r, uint32_t *w, uint32_t *e, uint64_t *time); diff --git a/k210-freertos/platform/drivers/w25qxx.c b/k210-freertos/platform/drivers/w25qxx.c index 157c382..3666901 100644 --- a/k210-freertos/platform/drivers/w25qxx.c +++ b/k210-freertos/platform/drivers/w25qxx.c @@ -63,6 +63,12 @@ static uint32_t er_count; static uint64_t op_time; // used only by 'w25qxx_write_data' uint8_t __attribute__((aligned(8))) swap_buf[w25qxx_FLASH_SECTOR_SIZE]; +bool w25qxx_swap_dat = true; + +// pointers for XIP reads +uint8_t *w25qxx_flash_ptr = (uint8_t *)SPI3_BASE_ADDR; +uint16_t *w25qxx_flash_ptr16 = (uint16_t *)SPI3_BASE_ADDR; +uint32_t *w25qxx_flash_ptr32 = (uint32_t *)SPI3_BASE_ADDR; //-------------------------------------------------------------------------------------------------------------------- static enum w25qxx_status_t w25qxx_receive_data(uint8_t* cmd_buff, uint8_t cmd_len, uint8_t* rx_buff, uint32_t rx_len) @@ -189,44 +195,29 @@ static enum w25qxx_status_t w25qxx_enable_quad_mode(void) 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_jedec_id(uint8_t *jedec_id) -{ - uint8_t cmd[1] = {READ_JEDEC_ID}; - - w25qxx_receive_data(cmd, 1, jedec_id, 3); - return W25QXX_OK; -} - -//--------------------------------------------------------- -enum w25qxx_status_t w25qxx_read_unique(uint8_t *unique_id) -{ - uint8_t cmd[5] = {READ_UNIQUE, 0x00, 0x00, 0x00, 0x00}; - - w25qxx_receive_data(cmd, 5, unique_id, 8); - return W25QXX_OK; -} - - // ==== Flash read functions ===================================================================== //------------------------------------------------------------------------------------------------------------------------------ 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) { + if ((rx_len % (FRAME_LENGTH_QUAD/8))) { + LOGE("w25qxx_receive", "Wrong Rx length (%u)", rx_len); + return W25QXX_ERROR; + } memcpy(rx_buff, cmd_buff, cmd_len); io_read(spi_adapter, (uint8_t *)rx_buff, rx_len); + if (w25qxx_swap_dat) { + // swap read data + uint8_t val; + for (uint32_t i=0; i> 16); @@ -328,42 +323,50 @@ enum w25qxx_status_t w25qxx_sector_erase(uint32_t addr) // Program the flash page (256 bytes) //------------------------------------------------------------------------------------------------ -static enum w25qxx_status_t w25qxx_page_program(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) { - uint8_t *read_buf = NULL; + uint8_t dbuff[w25qxx_FLASH_PAGE_SIZE]; int retry = 0; - if (w25qxx_spi_check) read_buf = pvPortMalloc(length); uint32_t cmd[2]; start: w25qxx_write_enable(); if (work_trans_mode == SPI_FF_QUAD) { + if (w25qxx_swap_dat) { + // Swap buffer data + for (uint32_t i=0; i> 0); *(((uint8_t*)cmd) + 2) = (uint8_t)(addr >> 8); *(((uint8_t*)cmd) + 3) = (uint8_t)(addr >> 16); - w25qxx_send_data(spi_adapter_wr, (uint8_t*)cmd, 4, data_buf, length); + w25qxx_send_data(spi_adapter_wr, (uint8_t*)cmd, 4, dbuff, w25qxx_FLASH_PAGE_SIZE); } else { *(((uint8_t*)cmd) + 0) = PAGE_PROGRAM; *(((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_send_data(spi_stand, (uint8_t*)cmd, 4, data_buf, length); + w25qxx_send_data(spi_stand, (uint8_t*)cmd, 4, data_buf, w25qxx_FLASH_PAGE_SIZE); } wr_count++; enum w25qxx_status_t res = w25qxx_wait_busy(); if (res != W25QXX_OK) return res; if (w25qxx_spi_check) { - _w25qxx_read_data(addr, read_buf, length); - if (memcmp(data_buf, read_buf, length) != 0) { + _w25qxx_read_data(addr, dbuff, w25qxx_FLASH_PAGE_SIZE); + if (memcmp(data_buf, dbuff, w25qxx_FLASH_PAGE_SIZE) != 0) { retry++; if (retry < 3) goto start; res = W25QXX_ERROR; } } - if (read_buf) vPortFree(read_buf); return res; } @@ -374,7 +377,7 @@ static enum w25qxx_status_t w25qxx_sector_program(uint32_t addr, uint8_t* data_b uint8_t index; for (index = 0; index < w25qxx_FLASH_PAGE_NUM_PER_SECTOR; index++) { - enum w25qxx_status_t res = w25qxx_page_program(addr, data_buf, w25qxx_FLASH_PAGE_SIZE); + enum w25qxx_status_t res = w25qxx_page_program(addr, data_buf); if (res != W25QXX_OK) return res; addr += w25qxx_FLASH_PAGE_SIZE; data_buf += w25qxx_FLASH_PAGE_SIZE; @@ -383,7 +386,7 @@ static enum w25qxx_status_t w25qxx_sector_program(uint32_t addr, uint8_t* data_b } // Write data buffer of arbitrary length to flash address 'addr' -//--------------------------------------------------------------------------------------- +//======================================================================================= enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t* data_buf, uint32_t length) { uint32_t sector_addr, sector_offset, sector_remain, write_len, index; @@ -452,7 +455,7 @@ enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t* data_buf, uint32_ return W25QXX_OK; } -//--------------------------------------------------------------------- +//===================================================================== uint32_t w25qxx_init(uintptr_t spi_in, uint8_t mode, double clock_rate) { configASSERT(mode < 3); @@ -469,7 +472,7 @@ uint32_t w25qxx_init(uintptr_t spi_in, uint8_t mode, double clock_rate) clock_rate = 40000000; } - spi_stand = spi_get_device(spi_in, SPI_MODE_0, SPI_FF_STANDARD, CHIP_SELECT, FRAME_LENGTH); + spi_stand = spi_get_device(spi_in, SPI_MODE_0, SPI_FF_STANDARD, CHIP_SELECT, FRAME_LENGTH_SINGLE); w25qxx_actual_speed = (uint32_t)spi_dev_set_clock_rate(spi_stand, SPI_STAND_CLOCK_RATE); w25qxx_read_id(&manuf_id, &device_id); @@ -504,7 +507,10 @@ uint32_t w25qxx_init(uintptr_t spi_in, uint8_t mode, double clock_rate) return w25qxx_actual_speed; } -//----------------------------------------------- + +// ==== Flash special functions ================================================================== + +//=============================================== enum w25qxx_status_t w25qxx_enable_xip_mode(void) { if (!spi_adapter) return W25QXX_ERROR; @@ -512,7 +518,7 @@ enum w25qxx_status_t w25qxx_enable_xip_mode(void) return W25QXX_OK; } -//------------------------------------------------ +//================================================ enum w25qxx_status_t w25qxx_disable_xip_mode(void) { if (!spi_adapter) return W25QXX_ERROR; @@ -520,6 +526,38 @@ enum w25qxx_status_t w25qxx_disable_xip_mode(void) 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_jedec_id(uint8_t *jedec_id) +{ + uint8_t cmd[1] = {READ_JEDEC_ID}; + + w25qxx_receive_data(cmd, 1, jedec_id, 3); + return W25QXX_OK; +} + +//========================================================= +enum w25qxx_status_t w25qxx_read_unique(uint8_t *unique_id) +{ + uint8_t cmd[5] = {READ_UNIQUE, 0x00, 0x00, 0x00, 0x00}; + + w25qxx_receive_data(cmd, 5, unique_id, 8); + return W25QXX_OK; +} + +// ==== Driver counter functions ================================================================= + //-------------------------- void w25qxx_clear_counters() { @@ -537,3 +575,4 @@ void w25qxx_get_counters(uint32_t *r, uint32_t *w, uint32_t *e, uint64_t *time) if (e) *e = er_count; if (time) *time = op_time; } + diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_3_5M.ld b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_3_5M.ld deleted file mode 100644 index aea3cd2..0000000 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lds/kendryte_kboot_3_5M.ld +++ /dev/null @@ -1,277 +0,0 @@ -/* - * 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. - */ - /* - * LoBo: The LENGTH specified here must be enough to run the MicroPython firmware - * including creating all static, global and dynamic variables on K210 heap - */ - - -MEMORY -{ - /* - * Memory with CPU cache. - * CPU SRAM - */ - ram (wxa!ri) : ORIGIN = 0x80002000, LENGTH = (0x380000-0x2000) - /* - * Memory without CPU cache - * CPU SRAM - */ - ram_nocache (wxa!ri) : ORIGIN = 0x40002000, LENGTH = (0x380000-0x2000) -} - -PROVIDE( _ram_end = ORIGIN(ram) + LENGTH(ram) ); -PROVIDE( _stack_size = 1 << 16 ); - -/* - * 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 linker only pays attention to the PHDRS command when generating - * an ELF output file. In other cases, the linker will simply ignore PHDRS. - */ -PHDRS -{ - DATA PT_LOAD; - DYN_DATA PT_NULL; -} - -/* - * This is where we specify how the input sections map to output - * sections. - */ -SECTIONS -{ - .text.start : - { - KEEP( *(.text.start) ) - KEEP( *(.text.systick) ) - } > ram : DATA - - .init : - { - KEEP (*(SORT_NONE(.init))) - } > ram : DATA - - . = ALIGN(8); - . = .; - .text : - { - *(.text.unlikely .text.*_unlikely .text.unlikely.*) - *(.text.exit .text.exit.*) - *(.text.startup .text.startup.*) - *(.text.hot .text.hot.*) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } > ram : DATA - - .fini : - { - KEEP (*(SORT_NONE(.fini))) - } > ram : DATA - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } > ram : DATA - .rodata1 : { *(.rodata1) } > ram : DATA - .sdata2 : - { - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - } > ram : DATA - /* Exception handling */ - .eh_frame : - { - KEEP (*(.eh_frame)) *(.eh_frame.*) - . = ALIGN(8); - } > ram : DATA - .gnu_extab : { *(.gnu_extab) } > ram : DATA - .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) } > ram : DATA - .exception_ranges : { *(.exception_ranges .exception_ranges*) } > ram : DATA - - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } > ram : DATA - .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 : DATA - .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 : DATA - - .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 : DATA - .dtors : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*crtbegin?.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } > ram : DATA - - . = ALIGN(64); - .data : - { - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } > ram : DATA - .data1 : { *(.data1) } > ram : DATA - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : - { - __global_pointer$ = . + 0x800; - *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) - *(.sdata .sdata.* .gnu.linkonce.s.*) - } > ram : DATA - _edata = .; PROVIDE (edata = .); - - . = ALIGN(8); - . = .; - __bss_start = .; - .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } > ram : DYN_DATA - .sbss : - { - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - } > ram : DYN_DATA - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 64 / 8 : 1); - } > ram : DYN_DATA - __bss_end = .; - - 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 : DATA - - /* Thread-local bss segment, .tbss (zero-initialized tls). */ - .tbss : - { - *(.tbss .tbss.*) - *(.gnu.linkonce.tb.*) - KEEP( *(.tbss.end) ) - } > ram : DYN_DATA - - /* - * 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); - _end = .; PROVIDE( _end = ABSOLUTE(.) ); - /* Leave 2 holes for stack & TLS, the size can set in kconfig */ - PROVIDE( _heap_start = ABSOLUTE(.) + _stack_size * 5 ); - 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 ); - - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } -} - diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/arch/include/iomem.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/arch/include/iomem.h index 5c3d529..84fd06d 100755 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/arch/include/iomem.h +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/arch/include/iomem.h @@ -25,7 +25,7 @@ extern "C" #include #include -#define FIX_CACHE 1 +#define FIX_CACHE 0 // LoBo #define IOMEM_BLOCK_SIZE 256 void iomem_free(void *paddr) ; diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/dmac.cpp b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/dmac.cpp index 231a48a..cdaa720 100755 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/dmac.cpp +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/dmac.cpp @@ -241,11 +241,17 @@ class k_dma_driver : public dma_driver, public static_object, public exclusive_o if (!mem_type_src) { + if (src >= (void *)0x80600000) { + LOGW("[DMAC]", "SRC at %p used", alloc_mem); + } dma.sar = (uint64_t)src; dma.dar = (uint64_t)alloc_mem; } else if (!mem_type_dest) { + if (src >= (void *)0x80600000) { + LOGW("[DMAC]", "DEST at %p used", alloc_mem); + } if (old_elm_size == 1) { size_t i; diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/spi.cpp b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/spi.cpp index 7f7d150..cf61016 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/spi.cpp +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/spi.cpp @@ -37,7 +37,7 @@ using namespace sys; // transmission length (frames) bellow which DMA transfer is not used // used only by SPI master // during the non-DMA transfer interrupts are disabled ! -#define SPI_TRANSMISSION_THRESHOLD 0x400UL // byte threshold above which a DMA transfer is used +#define SPI_TRANSMISSION_THRESHOLD 0x100000UL //0x400UL // byte threshold above which a DMA transfer is used #define SPI_DMA_BLOCK_TIME 1000UL // DMA transfer block time in ms #define SPI_SLAVE_INFO "K210 v1.2" // !must be exactly 9 bytes! @@ -189,7 +189,7 @@ class k_spi_driver : public spi_driver, public static_object, public free_object sysctl_reset(SYSCTL_RESET_SPI2); sysctl_clock_enable(SYSCTL_CLOCK_SPI2); sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI2, 4); - LOGD(SLAVE_TAG, "SPI Clk: %u", sysctl_clock_get_freq(SYSCTL_CLOCK_SPI2)); + LOGV(SLAVE_TAG, "SPI Clk: %u", sysctl_clock_get_freq(SYSCTL_CLOCK_SPI2)); uint32_t data_width = data_bit_length / 8; @@ -273,7 +273,7 @@ class k_spi_driver : public spi_driver, public static_object, public free_object spi_handle.imr = 0x10; if (irq_en) spi_handle.ssienr = 0x01; - LOGD(SLAVE_TAG, "In IDLE mode"); + LOGV(SLAVE_TAG, "In IDLE mode"); } // Wait for DMA transfer initiated from command handler to finish @@ -307,7 +307,7 @@ class k_spi_driver : public spi_driver, public static_object, public free_object } tend = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); if ((dmac_intstatus & 0x02) == 0) f = false; - LOGD(SLAVE_TAG, "Transfer time: %lu us)", tend - tstart); + LOGV(SLAVE_TAG, "Transfer time: %lu us)", tend - tstart); return f; } @@ -626,7 +626,7 @@ class k_spi_driver : public spi_driver, public static_object, public free_object // execute the callback function if set if (driver.slave_instance_.callback != NULL) driver.slave_instance_.callback((void *)&driver.slave_instance_.command); - LOGD(SLAVE_TAG, "Prepare time: %lu us", end_time_us - time_us); + LOGV(SLAVE_TAG, "Prepare time: %lu us", end_time_us - time_us); spi_slave_idle_mode(userdata, (driver.slave_instance_.command.err != SPI_CMD_ERR_FATAL)); return; } @@ -819,10 +819,16 @@ object_ptr k_spi_driver::get_device(spi_mode_t mode, spi_fram // LoBo: added function bool k_spi_driver::set_xip_mode(k_spi_device_driver &device, bool enable) { - // ToDo: check if device is spi3 + // XiP mode can only be enabled on SPI3 in QUAD mode + if (&spi_ != (volatile spi_t *)SPI3_BASE_ADDR) { + LOGE(TAG, "XiP enable: not an SPI3 device"); + return false; + } if (device.frame_format_ != SPI_FF_QUAD) { + LOGE(TAG, "XiP enable: not in QUAD mode"); return false; } + if (enable) { spi_.xip_ctrl = (0x01 << 29) | (0x02 << 26) | (0x01 << 23) | (0x01 << 22) | (0x04 << 13) | (0x01 << 12) | (0x02 << 9) | (0x06 << 4) | (0x01 << 2) | 0x02; @@ -860,8 +866,9 @@ double k_spi_driver::set_clock_rate(k_spi_device_driver &device, double clock_ra double clk = (double)sysctl_clock_get_freq(clock_); uint32_t div = std::min(65534U, std::max((uint32_t)ceil(clk / clock_rate), 2U)); if (div & 1) div++; // only even divisors allowed + if (device.baud_rate_ != div) + LOGV(TAG, "SPI_%d Bdr: clk=%u, div=%u, bdr=%u", clock_ - SYSCTL_CLOCK_SPI0, (uint32_t)clk, div, (uint32_t)(clk / div)); device.baud_rate_ = div; - LOGD(TAG, "SPI_%d Bdr: clk=%u, div=%u, bdr=%u", clock_ - SYSCTL_CLOCK_SPI0, (uint32_t)clk, div, (uint32_t)(clk / div)); return clk / div; } @@ -926,7 +933,7 @@ static int _wait_DMA_transfer(SemaphoreHandle_t dma_event1, SemaphoreHandle_t dm } } tend = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); - LOGD(TAG, "Transfer time: %lu us)", tend - tstart); + LOGV(TAG, "Transfer time: %lu us)", tend - tstart); return ret; } diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/iomem.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/iomem.c index 31e1aa2..e64c8d6 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/iomem.c +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/iomem.c @@ -13,18 +13,19 @@ * limitations under the License. */ #include -#include +//#include #include #include #include "FreeRTOS.h" #include "task.h" +#include "syslog.h" -// LoBo: some fixes in data typed and unused variables +// LoBo: some fixes in data types and unused variables typedef struct _iomem_malloc_t { void (*init)(); - uint32_t (*unused)(); + uint32_t (*unused)(); // LoBo: set as uint32_t uint8_t *membase; uint32_t memsize; uint32_t memtblsize; @@ -37,13 +38,14 @@ static _lock_t iomem_lock; static void iomem_init(); static uint32_t k_unused(); + extern char *_ioheap_line; extern char *_heap_line; +// Lobo: commented //extern char _heap_start[]; //extern char *_heap_cur; -iomem_malloc_t malloc_cortol = -{ +iomem_malloc_t malloc_controll = { iomem_init, k_unused, NULL, @@ -63,20 +65,20 @@ static void iomem_set(void *s, uint8_t c, uint32_t num) static void iomem_init() { - malloc_cortol.membase = (uint8_t *)((uintptr_t)_heap_line-0x40000000); - malloc_cortol.memsize = (uintptr_t)_ioheap_line - (uintptr_t)malloc_cortol.membase; + malloc_controll.membase = (uint8_t *)((uintptr_t)_heap_line-0x40000000); + malloc_controll.memsize = (uintptr_t)_ioheap_line - (uintptr_t)malloc_controll.membase; - malloc_cortol.memtblsize = malloc_cortol.memsize / IOMEM_BLOCK_SIZE; - malloc_cortol.memmap = (uint16_t *)malloc(malloc_cortol.memtblsize * 2); + malloc_controll.memtblsize = malloc_controll.memsize / IOMEM_BLOCK_SIZE; + malloc_controll.memmap = (uint16_t *)malloc(malloc_controll.memtblsize * 2); mb(); - malloc_cortol.membase = (uint8_t *)((uintptr_t)_heap_line-0x40000000); - malloc_cortol.memsize = (uintptr_t)_ioheap_line - (uintptr_t)malloc_cortol.membase; - malloc_cortol.memtblsize = malloc_cortol.memsize / IOMEM_BLOCK_SIZE; + malloc_controll.membase = (uint8_t *)((uintptr_t)_heap_line-0x40000000); + malloc_controll.memsize = (uintptr_t)_ioheap_line - (uintptr_t)malloc_controll.membase; + malloc_controll.memtblsize = malloc_controll.memsize / IOMEM_BLOCK_SIZE; - iomem_set(malloc_cortol.memmap, 0, malloc_cortol.memtblsize * 2); - iomem_set(malloc_cortol.membase, 0, malloc_cortol.memsize); - malloc_cortol.memrdy = 1; + iomem_set(malloc_controll.memmap, 0, malloc_controll.memtblsize * 2); + iomem_set(malloc_controll.membase, 0, malloc_controll.memsize); + malloc_controll.memrdy = 1; } static uint32_t k_unused() @@ -88,35 +90,36 @@ static uint32_t k_unused() return unused; } +#if FIX_CACHE static uint32_t k_malloc(uint32_t size) { signed long offset = 0; uint32_t xmemb; uint32_t kmemb = 0; //uint32_t i; - if(!malloc_cortol.memrdy) - malloc_cortol.init(); + if(!malloc_controll.memrdy) + malloc_controll.init(); if(size==0) return 0XFFFFFFFF; xmemb=size / IOMEM_BLOCK_SIZE; if(size % IOMEM_BLOCK_SIZE) xmemb++; - for(offset=malloc_cortol.memtblsize-1; offset>=0; offset--) + for(offset=malloc_controll.memtblsize-1; offset>=0; offset--) { - if(!malloc_cortol.memmap[offset]) + if(!malloc_controll.memmap[offset]) { kmemb++; } else { - offset = offset - malloc_cortol.memmap[offset] + 1; + offset = offset - malloc_controll.memmap[offset] + 1; kmemb=0; } if(kmemb==xmemb) { - malloc_cortol.memmap[offset] = xmemb; - malloc_cortol.memmap[offset+xmemb-1] = xmemb; + malloc_controll.memmap[offset] = xmemb; + malloc_controll.memmap[offset+xmemb-1] = xmemb; return (offset * IOMEM_BLOCK_SIZE); } } @@ -126,20 +129,20 @@ static uint32_t k_malloc(uint32_t size) static uint8_t k_free(uint32_t offset) { //int i; - if(!malloc_cortol.memrdy) + if(!malloc_controll.memrdy) { - malloc_cortol.init(); + malloc_controll.init(); return 1; } - if(offset < malloc_cortol.memsize) + if(offset < malloc_controll.memsize) { int index=offset / IOMEM_BLOCK_SIZE; - int nmemb=malloc_cortol.memmap[index]; + int nmemb=malloc_controll.memmap[index]; - malloc_cortol.memmap[index] = 0; - malloc_cortol.memmap[index+nmemb-1] = 0; + malloc_controll.memmap[index] = 0; + malloc_controll.memmap[index+nmemb-1] = 0; - if((uintptr_t)_ioheap_line == (uintptr_t)malloc_cortol.membase + offset) + if((uintptr_t)_ioheap_line == (uintptr_t)malloc_controll.membase + offset) { _ioheap_line = (char *)((uintptr_t)_ioheap_line + nmemb * IOMEM_BLOCK_SIZE); } @@ -149,18 +152,19 @@ static uint8_t k_free(uint32_t offset) return 2; } -static volatile uint32_t mstatus_t = 0; +//static volatile uint32_t mstatus_t = 0; +#endif void iomem_free(void *paddr) { - uint32_t offset; if(paddr == NULL) return; #if FIX_CACHE - _lock_acquire_recursive(malloc_cortol.lock); - offset=(uintptr_t)paddr - (uintptr_t)malloc_cortol.membase; + uint32_t offset; + _lock_acquire_recursive(malloc_controll.lock); + offset=(uintptr_t)paddr - (uintptr_t)malloc_controll.membase; k_free(offset); - _lock_release_recursive(malloc_cortol.lock); + _lock_release_recursive(malloc_controll.lock); #else free(paddr); #endif @@ -168,11 +172,11 @@ void iomem_free(void *paddr) void iomem_free_isr(void *paddr) { - uint32_t offset; if(paddr == NULL) return; #if FIX_CACHE - offset=(uintptr_t)paddr - (uintptr_t)malloc_cortol.membase; + uint32_t offset; + offset=(uintptr_t)paddr - (uintptr_t)malloc_controll.membase; k_free(offset); #endif } @@ -180,28 +184,28 @@ void iomem_free_isr(void *paddr) void *iomem_malloc(uint32_t size) { #if FIX_CACHE - _lock_acquire_recursive(malloc_cortol.lock); + _lock_acquire_recursive(malloc_controll.lock); uint32_t offset; offset=k_malloc(size); if(offset == 0XFFFFFFFF) { - printk("IOMEM malloc OUT of MEMORY!\r\n"); - _lock_release_recursive(malloc_cortol.lock); + LOGW("[IOMEM]", "IOMEM malloc OUT of MEMORY!\r\n"); + _lock_release_recursive(malloc_controll.lock); return NULL; } else { - if((uintptr_t)_ioheap_line > (uintptr_t)malloc_cortol.membase + offset) + if((uintptr_t)_ioheap_line > (uintptr_t)malloc_controll.membase + offset) { - _ioheap_line = (char *)((uintptr_t)malloc_cortol.membase + offset); + _ioheap_line = (char *)((uintptr_t)malloc_controll.membase + offset); if((uintptr_t)_ioheap_line < (uintptr_t)_heap_line-0x40000000) { - printk("WARNING: iomem heap line < cache heap line!\r\n"); + LOGW("[IOMEM]", "WARNING: iomem heap line (%p) < cache heap line (%p) !\r\n", _ioheap_line, _heap_line-0x40000000); } }; - _lock_release_recursive(malloc_cortol.lock); - return (void*)((uintptr_t)malloc_cortol.membase + offset); + _lock_release_recursive(malloc_controll.lock); + return (void*)((uintptr_t)malloc_controll.membase + offset); } #else return malloc(size); @@ -210,7 +214,7 @@ void *iomem_malloc(uint32_t size) uint32_t iomem_unused() { - return malloc_cortol.unused(); + return malloc_controll.unused(); } uint32_t is_memory_cache(uintptr_t address) diff --git a/micropython/ACKNOWLEDGEMENTS b/micropython/ACKNOWLEDGEMENTS index 65f731b..41ed6bf 100644 --- a/micropython/ACKNOWLEDGEMENTS +++ b/micropython/ACKNOWLEDGEMENTS @@ -762,7 +762,6 @@ today. The names appear in order of pledging. 1642 Udine 1643 Simon Critchley 1644 Sven Haiges, Germany - 1645 Yi Qing Sim 1646 "silicium" ("silicium_one", if "silicium" is busy) 1648 Andy O'Malia, @andyomalia 1650 RedCamelApps.com diff --git a/micropython/CODEOFCONDUCT.md b/micropython/CODEOFCONDUCT.md new file mode 100644 index 0000000..07cf877 --- /dev/null +++ b/micropython/CODEOFCONDUCT.md @@ -0,0 +1,53 @@ +MicroPython Code of Conduct +=========================== + +The MicroPython community is made up of members from around the globe with a +diverse set of skills, personalities, and experiences. It is through these +differences that our community experiences great successes and continued growth. +When you're working with members of the community, this Code of Conduct will +help steer your interactions and keep MicroPython a positive, successful, and +growing community. + +Members of the MicroPython community are open, considerate, and respectful. +Behaviours that reinforce these values contribute to a positive environment, and +include: acknowledging time and effort, being respectful of differing viewpoints +and experiences, gracefully accepting constructive criticism, and using +welcoming and inclusive language. + +Every member of our community has the right to have their identity respected. +The MicroPython community is dedicated to providing a positive experience for +everyone, regardless of age, gender identity and expression, sexual orientation, +disability, physical appearance, body size, ethnicity, nationality, race, or +religion (or lack thereof), education, or socio-economic status. + +Unacceptable behaviour includes: harassment, trolling, deliberate intimidation, +violent threats or language directed against another person; insults, put downs, +or jokes that are based upon stereotypes, that are exclusionary, or that hold +others up for ridicule; unwelcome sexual attention or advances; sustained +disruption of community discussions; publishing others' private information +without explicit permission; and other conduct that is inappropriate for a +professional audience including people of many different backgrounds. + +This code of conduct covers all online and offline presence related to the +MicroPython project, including GitHub and the forum. If a participant engages +in behaviour that violates this code of conduct, the MicroPython team may take +action as they deem appropriate, including warning the offender or expulsion +from the community. Community members asked to stop any inappropriate behaviour +are expected to comply immediately. + +Thank you for helping make this a welcoming, friendly community for everyone. + +If you believe that someone is violating the code of conduct, or have any other +concerns, please contact a member of the MicroPython team by emailing +contact@micropython.org. + +License +------- + +This Code of Conduct is licensed under the Creative Commons +Attribution-ShareAlike 3.0 Unported License. + +Attributions +------------ + +Based on the Python code of conduct found at https://www.python.org/psf/conduct/ diff --git a/micropython/LICENSE b/micropython/LICENSE index e3474e3..e6a54cf 100644 --- a/micropython/LICENSE +++ b/micropython/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013, 2014 Damien P. George +Copyright (c) 2013-2019 Damien P. George Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/micropython/README.md b/micropython/README.md index a393f50..8d0fd15 100644 --- a/micropython/README.md +++ b/micropython/README.md @@ -4,19 +4,50 @@ This is the clone of the main [MicroPython repository](https://github.com/micropython/micropython).

It is mostly unchanged, except for the following files:
-* `py/mpthread.h` & `py/modthread.c`
completelly rewritten thread support -* `py/obj.h`
changes needed for correct interpretation of floats for `MICROPY_OBJ_REPR_C` and `MICROPY_OBJ_REPR_D` for RISC-V 64bit processor -* `py/mpprint.c`
changes needed for usin `ll` for 64-bit integers (`MICROPY_OBJ_REPR_C`) -* `py/runtime.c`, `py/builtin.h`, `py/gc.c`, `py/gc.h`, `py/mpstate.h`
small changes to enable support for two MicroPython instances running on two processors -* `py/modsys.c`
small changes to enable support for two MicroPython instances running on two processors
**`sys.path`, `sys.argv` _and_ `sys.modules` _are now FUNCTIONS:_ `sys.path()`, `sys.argv()` _and_ `sys.modules()`** -* `py/modmicropython.c`
added PyStack info in `mem_info` function -* `py/compile.c`, `persistentcode.c`
small changes to address some errors when compiling without any native emmiter enabled -* `py/machine_mem.c`, `py/machine_mem.h`
added support for 64-bit memory objects -* `extmod/modframebuf.c`
added some functions (circle, fill_circle) -* `extmod/modlwip.c`
renamed to `extmod/modlwip.c.orig` to prevent compiling as it is not used -* `tools/mpy-tool.py`
changes needed for correct interpretation of floats for `MICROPY_OBJ_REPR_C` for RISC-V 64bit processor -* `lib/utils/pyexec.c`
changed printing of version info string -* small changes in all files dealing with PyStack
`MICROPY_ENABLE_PYSTACK` conditional compiles was changed to runtime check for PyStack enabled.
If PyStack is used or not can be changed in MicroPython configuration. +* Renamed unused files to prevent compiling + * `extmod/modlwip.c` --> `extmod/modlwip.c.orig` +* Completelly rewritten thread support + * `py/mpthread.h` + * `py/modthread.c` +* Changes needed for correct interpretation of floats for `MICROPY_OBJ_REPR_C` and `MICROPY_OBJ_REPR_D` for RISC-V 64bit processor + * `py/obj.h` +* Changes needed for using `ll` for 64-bit integers (`MICROPY_OBJ_REPR_C`) + * `py/mpprint.c` +* Small changes to enable support for two MicroPython instances running on two processors: + * `py/runtime.c` + * `py/builtin.h` + * `py/gc.c`, + * `py/gc.h` + * `py/mpstate.h` +* Small changes to enable support for two MicroPython instances running on two processors
**`sys.path`, `sys.argv` _and_ `sys.modules` _are now FUNCTIONS:_ `sys.path()`, `sys.argv()` _and_ `sys.modules()`** + * `py/modsys.c` +* Added PyStack info in `mem_info` function + * `py/modmicropython.c` +* Small changes to address some errors when compiling without any native emmiter enabled + * `py/compile.c` + * `py/persistentcode.c` +* Added support for 64-bit memory objects + * `extmod/machine_mem.c` + * `extmod/machine_mem.h` +* Added some functions (circle, fill_circle) + * `extmod/modframebuf.c` +* Changes needed for correct interpretation of floats for `MICROPY_OBJ_REPR_C` for RISC-V 64bit processor + * `tools/mpy-tool.py` +* Changed printing of version info string + * `lib/utils/pyexec.c`
+* Small changes in all files dealing with PyStack
`MICROPY_ENABLE_PYSTACK` conditional compiles was changed to runtime check for PyStack enabled.
If PyStack is used or not can be changed in MicroPython configuration. + * `py/nlr.h` + * `py/objbountmeth.c` + * `py/objfun.c` + * `py/qstrdefs.h` + * `py/pystack.c` + * `py/pystack.h` + * `py/vm.c` +* Some changes in `mk` files for better integration with this port's build system + * `py/mkrules.mk` + * `py/mkenv.mk` +* Small change to avoid compiler errors when building on OSX + * `py/mpstate.c` *All modified files contains the copyright string* **"Copyright (c) 2019 LoBo (https://github.com/loboris)"** *and the changes are marked with the* **LoBo** *comment.*
All modifications are easy to maintain and should not present a problem when the MicroPython core is updated. @@ -25,13 +56,13 @@ All modifications are easy to maintain and should not present a problem when the *** -Latest update: May 29. 2019.
-Release: **1.11**
-SHA: `6f75c4f` (`6f75c4f3cd393131579db70cdf0b35d1fe5b95ab`) +Latest update: Dec 22. 2019.
+Release: **1.12**
+SHA: `1f37194` (`1f371947309c5ea6023b6d9065415697cbc75578`) *** -[MicroPython **Release information**](https://github.com/micropython/micropython/releases/tag/v1.11) +[MicroPython **Release information**](https://github.com/micropython/micropython/releases/tag/v1.12) [MicroPython **README.md**](https://github.com/micropython/micropython/blob/master/README.md) diff --git a/micropython/docs/conf.py b/micropython/docs/conf.py index 71e561c..8b4730a 100755 --- a/micropython/docs/conf.py +++ b/micropython/docs/conf.py @@ -74,7 +74,7 @@ # # We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags" # breakdown, so use the same version identifier for both to avoid confusion. -version = release = '1.11' +version = release = '1.12' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/micropython/extmod/crypto-algorithms/sha256.c b/micropython/extmod/crypto-algorithms/sha256.c index 276611c..24e9647 100644 --- a/micropython/extmod/crypto-algorithms/sha256.c +++ b/micropython/extmod/crypto-algorithms/sha256.c @@ -1,7 +1,8 @@ /********************************************************************* +* Source: https://github.com/B-Con/crypto-algorithms * Filename: sha256.c * Author: Brad Conte (brad AT bradconte.com) -* Copyright: +* Copyright: This code is released into the public domain. * Disclaimer: This code is presented "as is" without any guarantees. * Details: Implementation of the SHA-256 hashing algorithm. SHA-256 is one of the three algorithms in the SHA2 diff --git a/micropython/extmod/crypto-algorithms/sha256.h b/micropython/extmod/crypto-algorithms/sha256.h index caa1f81..9c19472 100644 --- a/micropython/extmod/crypto-algorithms/sha256.h +++ b/micropython/extmod/crypto-algorithms/sha256.h @@ -1,7 +1,8 @@ /********************************************************************* +* Source: https://github.com/B-Con/crypto-algorithms * Filename: sha256.h * Author: Brad Conte (brad AT bradconte.com) -* Copyright: +* Copyright: This code is released into the public domain. * Disclaimer: This code is presented "as is" without any guarantees. * Details: Defines the API for the corresponding SHA1 implementation. *********************************************************************/ diff --git a/micropython/extmod/machine_mem.c b/micropython/extmod/machine_mem.c index 833d096..3702eb9 100644 --- a/micropython/extmod/machine_mem.c +++ b/micropython/extmod/machine_mem.c @@ -107,7 +107,11 @@ STATIC mp_obj_t machine_mem_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t va } else { // store uintptr_t addr = MICROPY_MACHINE_MEM_GET_WRITE_ADDR(index, self->elem_size); - uintptr_t rambuf_addr = (MICROPY_SYS_RAMBUF_ADDR < K210_SRAM_START_ADDRESS) ? (MICROPY_SYS_RAMBUF_ADDR + 0x40000000UL) : MICROPY_SYS_RAMBUF_ADDR; + #if MICROPY_PY_USE_OTA + uintptr_t rambuf_addr_start = MICROPY_SYS_RAMBUF_ADDR+8; + #else + uintptr_t rambuf_addr_start = MICROPY_SYS_RAMBUF_ADDR; + #endif addr += K210_SRAM_START_ADDRESS; uint64_t val = 0; size_t val_len = 0; @@ -124,7 +128,7 @@ STATIC mp_obj_t machine_mem_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t va val_len = strlen(strval) + 1; } // ==== Only allow writing to system RAM buffer ! ==== - if ((addr < rambuf_addr) || (addr > (int64_t)(rambuf_addr + MYCROPY_SYS_RAMBUF_SIZE - val_len))) { + if ((addr < rambuf_addr_start) || (addr > (int64_t)(MICROPY_SYS_RAMBUF_ADDR + MYCROPY_SYS_RAMBUF_SIZE - val_len))) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "writing %lu bytes to address 0x%08x outside of RAM buffer", val_len, addr)); } switch (self->elem_size) { diff --git a/micropython/extmod/machine_pulse.c b/micropython/extmod/machine_pulse.c index 5f83747..7178b22 100644 --- a/micropython/extmod/machine_pulse.c +++ b/micropython/extmod/machine_pulse.c @@ -30,7 +30,7 @@ #if MICROPY_PY_MACHINE_PULSE -mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { +MP_WEAK mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { mp_uint_t start = mp_hal_ticks_us(); while (mp_hal_pin_read(pin) != pulse_level) { if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { diff --git a/micropython/extmod/misc.h b/micropython/extmod/misc.h index dae6bec..40b091e 100644 --- a/micropython/extmod/misc.h +++ b/micropython/extmod/misc.h @@ -36,6 +36,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj); #if MICROPY_PY_OS_DUPTERM bool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream); +uintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags); int mp_uos_dupterm_rx_chr(void); void mp_uos_dupterm_tx_strn(const char *str, size_t len); void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc); diff --git a/micropython/extmod/modbtree.c b/micropython/extmod/modbtree.c index a2bff06..a1d576f 100644 --- a/micropython/extmod/modbtree.c +++ b/micropython/extmod/modbtree.c @@ -52,7 +52,9 @@ typedef struct _mp_obj_btree_t { byte next_flags; } mp_obj_btree_t; +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_obj_type_t btree_type; +#endif #define CHECK_ERROR(res) \ if (res == RET_ERROR) { \ @@ -60,7 +62,7 @@ STATIC const mp_obj_type_t btree_type; } void __dbpanic(DB *db) { - printf("__dbpanic(%p)\n", db); + mp_printf(&mp_plat_print, "__dbpanic(%p)\n", db); } STATIC mp_obj_btree_t *btree_new(DB *db) { @@ -295,6 +297,7 @@ STATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs } } +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t btree_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&btree_close_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&btree_flush_obj) }, @@ -319,14 +322,16 @@ STATIC const mp_obj_type_t btree_type = { .subscr = btree_subscr, .locals_dict = (void*)&btree_locals_dict, }; +#endif -STATIC FILEVTABLE btree_stream_fvtable = { +STATIC const FILEVTABLE btree_stream_fvtable = { mp_stream_posix_read, mp_stream_posix_write, mp_stream_posix_lseek, mp_stream_posix_fsync }; +#if !MICROPY_ENABLE_DYNRUNTIME STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_flags, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, @@ -373,5 +378,6 @@ const mp_obj_module_t mp_module_btree = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_btree_globals, }; +#endif #endif // MICROPY_PY_BTREE diff --git a/micropython/extmod/modframebuf.c b/micropython/extmod/modframebuf.c index 9628151..1c9ae36 100644 --- a/micropython/extmod/modframebuf.c +++ b/micropython/extmod/modframebuf.c @@ -675,6 +675,7 @@ STATIC mp_obj_t framebuf_text(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_text_obj, 4, 5, framebuf_text); +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t framebuf_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&framebuf_fill_obj) }, { MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&framebuf_fill_rect_obj) }, @@ -698,6 +699,7 @@ STATIC const mp_obj_type_t mp_type_framebuf = { .buffer_p = { .get_buffer = framebuf_get_buffer }, .locals_dict = (mp_obj_dict_t*)&framebuf_locals_dict, }; +#endif // this factory function is provided for backwards compatibility with old FrameBuffer1 class STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args) { @@ -721,6 +723,7 @@ STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(legacy_framebuffer1_obj, 3, 4, legacy_framebuffer1); +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_framebuf) }, { MP_ROM_QSTR(MP_QSTR_FrameBuffer), MP_ROM_PTR(&mp_type_framebuf) }, @@ -741,5 +744,6 @@ const mp_obj_module_t mp_module_framebuf = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&framebuf_module_globals, }; +#endif #endif // MICROPY_PY_FRAMEBUF diff --git a/micropython/extmod/modlwip.c.orig b/micropython/extmod/modlwip.c.orig index 4127d21..4358544 100644 --- a/micropython/extmod/modlwip.c.orig +++ b/micropython/extmod/modlwip.c.orig @@ -40,7 +40,7 @@ #include "lwip/init.h" #include "lwip/tcp.h" #include "lwip/udp.h" -//#include "lwip/raw.h" +#include "lwip/raw.h" #include "lwip/dns.h" #include "lwip/igmp.h" #if LWIP_VERSION_MAJOR < 2 @@ -280,6 +280,7 @@ typedef struct _lwip_socket_obj_t { volatile union { struct tcp_pcb *tcp; struct udp_pcb *udp; + struct raw_pcb *raw; } pcb; volatile union { struct pbuf *pbuf; @@ -356,10 +357,31 @@ STATIC void lwip_socket_free_incoming(lwip_socket_obj_t *socket) { static inline void exec_user_callback(lwip_socket_obj_t *socket) { if (socket->callback != MP_OBJ_NULL) { - mp_call_function_1_protected(socket->callback, MP_OBJ_FROM_PTR(socket)); + // Schedule the user callback to execute outside the lwIP context + mp_sched_schedule(socket->callback, MP_OBJ_FROM_PTR(socket)); } } +#if MICROPY_PY_LWIP_SOCK_RAW +// Callback for incoming raw packets. +#if LWIP_VERSION_MAJOR < 2 +STATIC u8_t _lwip_raw_incoming(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) +#else +STATIC u8_t _lwip_raw_incoming(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) +#endif +{ + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + + if (socket->incoming.pbuf != NULL) { + pbuf_free(p); + } else { + socket->incoming.pbuf = p; + memcpy(&socket->peer, addr, sizeof(socket->peer)); + } + return 1; // we ate the packet +} +#endif + // Callback for incoming UDP packets. We simply stash the packet and the source address, // in case we need it for recvfrom. #if LWIP_VERSION_MAJOR < 2 @@ -446,18 +468,6 @@ STATIC err_t _lwip_tcp_recv_unaccepted(void *arg, struct tcp_pcb *pcb, struct pb return ERR_BUF; } -// "Poll" (idle) callback to be called ASAP after accept callback -// to execute Python callback function, as it can't be executed -// from accept callback itself. -STATIC err_t _lwip_tcp_accept_finished(void *arg, struct tcp_pcb *pcb) -{ - // The ->connected entry of the pcb holds the listening socket of the accept - lwip_socket_obj_t *socket = (lwip_socket_obj_t*)pcb->connected; - tcp_poll(pcb, NULL, 0); - exec_user_callback(socket); - return ERR_OK; -} - // Callback for incoming tcp connections. STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { // err can be ERR_MEM to notify us that there was no memory for an incoming connection @@ -476,12 +486,9 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { if (++socket->incoming.connection.iput >= socket->incoming.connection.alloc) { socket->incoming.connection.iput = 0; } - if (socket->callback != MP_OBJ_NULL) { - // Schedule accept callback to be called when lwIP is done - // with processing this incoming connection on its side and - // is idle. - tcp_poll(newpcb, _lwip_tcp_accept_finished, 1); - } + + // Schedule user accept callback + exec_user_callback(socket); // Set the error callback to handle the case of a dropped connection before we // have a chance to take it off the accept queue. @@ -529,8 +536,8 @@ STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err // Functions for socket send/receive operations. Socket send/recv and friends call // these to do the work. -// Helper function for send/sendto to handle UDP packets. -STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { +// Helper function for send/sendto to handle raw/UDP packets. +STATIC mp_uint_t lwip_raw_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { if (len > 0xffff) { // Any packet that big is probably going to fail the pbuf_alloc anyway, but may as well try len = 0xffff; @@ -550,11 +557,25 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui err_t err; if (ip == NULL) { - err = udp_send(socket->pcb.udp, p); + #if MICROPY_PY_LWIP_SOCK_RAW + if (socket->type == MOD_NETWORK_SOCK_RAW) { + err = raw_send(socket->pcb.raw, p); + } else + #endif + { + err = udp_send(socket->pcb.udp, p); + } } else { ip_addr_t dest; IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]); - err = udp_sendto(socket->pcb.udp, p, &dest, port); + #if MICROPY_PY_LWIP_SOCK_RAW + if (socket->type == MOD_NETWORK_SOCK_RAW) { + err = raw_sendto(socket->pcb.raw, p, &dest); + } else + #endif + { + err = udp_sendto(socket->pcb.udp, p, &dest, port); + } } pbuf_free(p); @@ -572,8 +593,8 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui return len; } -// Helper function for recv/recvfrom to handle UDP packets -STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { +// Helper function for recv/recvfrom to handle raw/UDP packets +STATIC mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { if (socket->incoming.pbuf == NULL) { if (socket->timeout != -1) { @@ -668,7 +689,25 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui u16_t write_len = MIN(available, len); - err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY); + // If tcp_write returns ERR_MEM then there's currently not enough memory to + // queue the write, so wait and keep trying until it succeeds (with 10s limit). + // Note: if the socket is non-blocking then this code will actually block until + // there's enough memory to do the write, but by this stage we have already + // committed to being able to write the data. + err_t err; + for (int i = 0; i < 200; ++i) { + err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY); + if (err != ERR_MEM) { + break; + } + err = tcp_output(socket->pcb.tcp); + if (err != ERR_OK) { + break; + } + MICROPY_PY_LWIP_EXIT + mp_hal_delay_ms(50); + MICROPY_PY_LWIP_REENTER + } // If the output buffer is getting full then send the data to the lower layers if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) { @@ -791,7 +830,13 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s socket->pcb.udp = udp_new(); socket->incoming.pbuf = NULL; break; - //case MOD_NETWORK_SOCK_RAW: socket->pcb.raw = raw_new(); break; + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: { + mp_int_t proto = n_args <= 2 ? 0 : mp_obj_get_int(args[2]); + socket->pcb.raw = raw_new(proto); + break; + } + #endif default: mp_raise_OSError(MP_EINVAL); } @@ -813,6 +858,14 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s udp_recv(socket->pcb.udp, _lwip_udp_incoming, (void*)socket); break; } + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: { + // Register our receive callback now. Since raw sockets don't require binding or connection + // before use, there's no other good time to do it. + raw_recv(socket->pcb.raw, _lwip_raw_incoming, (void*)socket); + break; + } + #endif } socket->timeout = -1; @@ -1041,6 +1094,12 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { err = udp_connect(socket->pcb.udp, &dest, port); break; } + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: { + err = raw_connect(socket->pcb.raw, &dest); + break; + } + #endif } if (err != ERR_OK) { @@ -1075,10 +1134,12 @@ STATIC mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) { ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno); break; } - case MOD_NETWORK_SOCK_DGRAM: { - ret = lwip_udp_send(socket, bufinfo.buf, bufinfo.len, NULL, 0, &_errno); + case MOD_NETWORK_SOCK_DGRAM: + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + ret = lwip_raw_udp_send(socket, bufinfo.buf, bufinfo.len, NULL, 0, &_errno); break; - } } if (ret == -1) { mp_raise_OSError(_errno); @@ -1104,10 +1165,12 @@ STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) { ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno); break; } - case MOD_NETWORK_SOCK_DGRAM: { - ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, NULL, NULL, &_errno); + case MOD_NETWORK_SOCK_DGRAM: + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + ret = lwip_raw_udp_receive(socket, (byte*)vstr.buf, len, NULL, NULL, &_errno); break; - } } if (ret == -1) { mp_raise_OSError(_errno); @@ -1139,10 +1202,12 @@ STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno); break; } - case MOD_NETWORK_SOCK_DGRAM: { - ret = lwip_udp_send(socket, bufinfo.buf, bufinfo.len, ip, port, &_errno); + case MOD_NETWORK_SOCK_DGRAM: + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + ret = lwip_raw_udp_send(socket, bufinfo.buf, bufinfo.len, ip, port, &_errno); break; - } } if (ret == -1) { mp_raise_OSError(_errno); @@ -1172,10 +1237,12 @@ STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno); break; } - case MOD_NETWORK_SOCK_DGRAM: { - ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, ip, &port, &_errno); + case MOD_NETWORK_SOCK_DGRAM: + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + ret = lwip_raw_udp_receive(socket, (byte*)vstr.buf, len, ip, &port, &_errno); break; - } } if (ret == -1) { mp_raise_OSError(_errno); @@ -1327,7 +1394,10 @@ STATIC mp_uint_t lwip_socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, i case MOD_NETWORK_SOCK_STREAM: return lwip_tcp_receive(socket, buf, size, errcode); case MOD_NETWORK_SOCK_DGRAM: - return lwip_udp_receive(socket, buf, size, NULL, NULL, errcode); + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + return lwip_raw_udp_receive(socket, buf, size, NULL, NULL, errcode); } // Unreachable return MP_STREAM_ERROR; @@ -1340,7 +1410,10 @@ STATIC mp_uint_t lwip_socket_write(mp_obj_t self_in, const void *buf, mp_uint_t case MOD_NETWORK_SOCK_STREAM: return lwip_tcp_send(socket, buf, size, errcode); case MOD_NETWORK_SOCK_DGRAM: - return lwip_udp_send(socket, buf, size, NULL, 0, errcode); + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: + #endif + return lwip_raw_udp_send(socket, buf, size, NULL, 0, errcode); } // Unreachable return MP_STREAM_ERROR; @@ -1381,6 +1454,11 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ if (socket->type == MOD_NETWORK_SOCK_DGRAM && socket->pcb.udp != NULL) { // UDP socket is writable ret |= MP_STREAM_POLL_WR; + #if MICROPY_PY_LWIP_SOCK_RAW + } else if (socket->type == MOD_NETWORK_SOCK_RAW && socket->pcb.raw != NULL) { + // raw socket is writable + ret |= MP_STREAM_POLL_WR; + #endif } else if (socket->pcb.tcp != NULL && tcp_sndbuf(socket->pcb.tcp) > 0) { // TCP socket is writable // Note: pcb.tcp==NULL if state<0, and in this case we can't call tcp_sndbuf @@ -1390,7 +1468,7 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ if (socket->state == STATE_NEW) { // New sockets are not connected so set HUP - ret |= flags & MP_STREAM_POLL_HUP; + ret |= MP_STREAM_POLL_HUP; } else if (socket->state == STATE_PEER_CLOSED) { // Peer-closed socket is both readable and writable: read will // return EOF, write - error. Without this poll will hang on a @@ -1398,11 +1476,14 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ ret |= flags & (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR); } else if (socket->state == ERR_RST) { // Socket was reset by peer, a write will return an error - ret |= flags & (MP_STREAM_POLL_WR | MP_STREAM_POLL_HUP); + ret |= flags & MP_STREAM_POLL_WR; + ret |= MP_STREAM_POLL_HUP; + } else if (socket->state == _ERR_BADF) { + ret |= MP_STREAM_POLL_NVAL; } else if (socket->state < 0) { // Socket in some other error state, use catch-all ERR flag // TODO: may need to set other return flags here - ret |= flags & MP_STREAM_POLL_ERR; + ret |= MP_STREAM_POLL_ERR; } } else if (request == MP_STREAM_CLOSE) { @@ -1434,7 +1515,9 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ break; } case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; - //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; + #if MICROPY_PY_LWIP_SOCK_RAW + case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; + #endif } socket->pcb.tcp = NULL; @@ -1656,7 +1739,9 @@ STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(MOD_NETWORK_SOCK_STREAM) }, { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(MOD_NETWORK_SOCK_DGRAM) }, + #if MICROPY_PY_LWIP_SOCK_RAW { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(MOD_NETWORK_SOCK_RAW) }, + #endif { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(1) }, { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SOF_REUSEADDR) }, diff --git a/micropython/extmod/moducryptolib.c b/micropython/extmod/moducryptolib.c index 15cd453..fd487a8 100644 --- a/micropython/extmod/moducryptolib.c +++ b/micropython/extmod/moducryptolib.c @@ -89,7 +89,7 @@ typedef struct _mp_obj_aes_t { uint8_t key_type: 2; } mp_obj_aes_t; -STATIC inline bool is_ctr_mode(int block_mode) { +static inline bool is_ctr_mode(int block_mode) { #if MICROPY_PY_UCRYPTOLIB_CTR return block_mode == UCRYPTOLIB_MODE_CTR; #else @@ -97,7 +97,7 @@ STATIC inline bool is_ctr_mode(int block_mode) { #endif } -STATIC inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) { +static inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) { // ctr_params follows aes object struct return (struct ctr_params*)&o[1]; } diff --git a/micropython/extmod/moductypes.c b/micropython/extmod/moductypes.c index 9b46371..62bbcba 100644 --- a/micropython/extmod/moductypes.c +++ b/micropython/extmod/moductypes.c @@ -299,13 +299,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, ucty static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) { char struct_type = big_endian ? '>' : '<'; static const char type2char[16] = "BbHhIiQq------fd"; - return mp_binary_get_val(struct_type, type2char[val_type], &p); + return mp_binary_get_val(struct_type, type2char[val_type], p, &p); } static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) { char struct_type = big_endian ? '>' : '<'; static const char type2char[16] = "BbHhIiQq------fd"; - mp_binary_set_val(struct_type, type2char[val_type], val, &p); + mp_binary_set_val(struct_type, type2char[val_type], val, p, &p); } static inline mp_uint_t get_aligned_basic(uint val_type, void *p) { @@ -558,7 +558,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS); arr_sz &= VALUE_MASK(VAL_TYPE_BITS); if (index >= arr_sz) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "struct: index out of range")); + mp_raise_msg(&mp_type_IndexError, "struct: index out of range"); } if (t->len == 2) { diff --git a/micropython/extmod/moduheapq.c b/micropython/extmod/moduheapq.c index bdaf191..2e80101 100644 --- a/micropython/extmod/moduheapq.c +++ b/micropython/extmod/moduheapq.c @@ -31,14 +31,14 @@ // the algorithm here is modelled on CPython's heapq.py -STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) { +STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) { if (!mp_obj_is_type(heap_in, &mp_type_list)) { mp_raise_TypeError("heap must be a list"); } return MP_OBJ_TO_PTR(heap_in); } -STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) { +STATIC void uheapq_heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) { mp_obj_t item = heap->items[pos]; while (pos > start_pos) { mp_uint_t parent_pos = (pos - 1) >> 1; @@ -53,7 +53,7 @@ STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t po heap->items[pos] = item; } -STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) { +STATIC void uheapq_heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) { mp_uint_t start_pos = pos; mp_uint_t end_pos = heap->len; mp_obj_t item = heap->items[pos]; @@ -67,42 +67,43 @@ STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) { pos = child_pos; } heap->items[pos] = item; - heap_siftdown(heap, start_pos, pos); + uheapq_heap_siftdown(heap, start_pos, pos); } STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) { - mp_obj_list_t *heap = get_heap(heap_in); + mp_obj_list_t *heap = uheapq_get_heap(heap_in); mp_obj_list_append(heap_in, item); - heap_siftdown(heap, 0, heap->len - 1); + uheapq_heap_siftdown(heap, 0, heap->len - 1); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush); STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) { - mp_obj_list_t *heap = get_heap(heap_in); + mp_obj_list_t *heap = uheapq_get_heap(heap_in); if (heap->len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); + mp_raise_msg(&mp_type_IndexError, "empty heap"); } mp_obj_t item = heap->items[0]; heap->len -= 1; heap->items[0] = heap->items[heap->len]; heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer if (heap->len) { - heap_siftup(heap, 0); + uheapq_heap_siftup(heap, 0); } return item; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop); STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) { - mp_obj_list_t *heap = get_heap(heap_in); + mp_obj_list_t *heap = uheapq_get_heap(heap_in); for (mp_uint_t i = heap->len / 2; i > 0;) { - heap_siftup(heap, --i); + uheapq_heap_siftup(heap, --i); } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify); +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t mp_module_uheapq_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uheapq) }, { MP_ROM_QSTR(MP_QSTR_heappush), MP_ROM_PTR(&mod_uheapq_heappush_obj) }, @@ -116,5 +117,6 @@ const mp_obj_module_t mp_module_uheapq = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_uheapq_globals, }; +#endif #endif //MICROPY_PY_UHEAPQ diff --git a/micropython/extmod/modujson.c b/micropython/extmod/modujson.c index f5c6428..15ed2f3 100644 --- a/micropython/extmod/modujson.c +++ b/micropython/extmod/modujson.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2014-2016 Damien P. George + * Copyright (c) 2014-2019 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -281,9 +281,9 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load); STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { - size_t len; - const char *buf = mp_obj_str_get_data(obj, &len); - vstr_t vstr = {len, len, (char*)buf, true}; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(obj, &bufinfo, MP_BUFFER_READ); + vstr_t vstr = {bufinfo.len, bufinfo.len, (char*)bufinfo.buf, true}; mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL}; return mod_ujson_load(MP_OBJ_FROM_PTR(&sio)); } diff --git a/micropython/extmod/modurandom.c b/micropython/extmod/modurandom.c index 2e66757..e3c7fc7 100644 --- a/micropython/extmod/modurandom.c +++ b/micropython/extmod/modurandom.c @@ -36,8 +36,10 @@ // http://www.literatecode.com/yasmarang // Public Domain +#if !MICROPY_ENABLE_DYNRUNTIME STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233; STATIC uint8_t yasmarang_dat = 0; +#endif STATIC uint32_t yasmarang(void) { @@ -208,6 +210,7 @@ STATIC mp_obj_t mod_urandom___init__() { STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__); #endif +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) }, #ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC @@ -232,5 +235,6 @@ const mp_obj_module_t mp_module_urandom = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_urandom_globals, }; +#endif #endif //MICROPY_PY_URANDOM diff --git a/micropython/extmod/modure.c b/micropython/extmod/modure.c index 0d5330c..f3a9d88 100644 --- a/micropython/extmod/modure.c +++ b/micropython/extmod/modure.c @@ -144,6 +144,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_end_obj, 1, 2, match_end); #endif +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t match_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_group), MP_ROM_PTR(&match_group_obj) }, #if MICROPY_PY_URE_MATCH_GROUPS @@ -164,6 +165,7 @@ STATIC const mp_obj_type_t match_type = { .print = match_print, .locals_dict = (void*)&match_locals_dict, }; +#endif STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; @@ -363,6 +365,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub); #endif +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t re_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) }, { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) }, @@ -380,8 +383,10 @@ STATIC const mp_obj_type_t re_type = { .print = re_print, .locals_dict = (void*)&re_locals_dict, }; +#endif STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { + (void)n_args; const char *re_str = mp_obj_str_get_str(args[0]); int size = re1_5_sizecode(re_str); if (size == -1) { @@ -389,18 +394,22 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { } mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size); o->base.type = &re_type; + #if MICROPY_PY_URE_DEBUG int flags = 0; if (n_args > 1) { flags = mp_obj_get_int(args[1]); } + #endif int error = re1_5_compilecode(&o->re, re_str); if (error != 0) { error: mp_raise_ValueError("Error in regex"); } + #if MICROPY_PY_URE_DEBUG if (flags & FLAG_DEBUG) { re1_5_dumpcode(&o->re); } + #endif return MP_OBJ_FROM_PTR(o); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile); @@ -432,6 +441,7 @@ STATIC mp_obj_t mod_re_sub(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub); #endif +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ure) }, { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) }, @@ -440,7 +450,9 @@ STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = { #if MICROPY_PY_URE_SUB { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) }, #endif + #if MICROPY_PY_URE_DEBUG { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table); @@ -449,13 +461,16 @@ const mp_obj_module_t mp_module_ure = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_re_globals, }; +#endif // Source files #include'd here to make sure they're compiled in // only if module is enabled by config setting. #define re1_5_fatal(x) assert(!x) #include "re1.5/compilecode.c" +#if MICROPY_PY_URE_DEBUG #include "re1.5/dumpcode.c" +#endif #include "re1.5/recursiveloop.c" #include "re1.5/charclass.c" diff --git a/micropython/extmod/modussl_axtls.c b/micropython/extmod/modussl_axtls.c index b559b13..2ea1757 100644 --- a/micropython/extmod/modussl_axtls.c +++ b/micropython/extmod/modussl_axtls.c @@ -54,7 +54,7 @@ struct ssl_args { STATIC const mp_obj_type_t ussl_socket_type; -STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { +STATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args) { #if MICROPY_PY_USSL_FINALISER mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); #else @@ -118,13 +118,13 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { return o; } -STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { +STATIC void ussl_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "<_SSLSocket %p>", self->ssl_sock); } -STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { +STATIC mp_uint_t ussl_socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); if (o->ssl_sock == NULL) { @@ -173,7 +173,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc return size; } -STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { +STATIC mp_uint_t ussl_socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); if (o->ssl_sock == NULL) { @@ -189,7 +189,7 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in return r; } -STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { +STATIC mp_uint_t ussl_socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); if (request == MP_STREAM_CLOSE && self->ssl_sock != NULL) { ssl_free(self->ssl_sock); @@ -200,7 +200,7 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode); } -STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { +STATIC mp_obj_t ussl_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in); mp_obj_t sock = o->sock; mp_obj_t dest[3]; @@ -210,14 +210,14 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { o->blocking = mp_obj_is_true(flag_in); return res; } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ussl_socket_setblocking_obj, ussl_socket_setblocking); STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&ussl_socket_setblocking_obj) }, { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, #if MICROPY_PY_USSL_FINALISER { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, @@ -227,16 +227,16 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table); STATIC const mp_stream_p_t ussl_socket_stream_p = { - .read = socket_read, - .write = socket_write, - .ioctl = socket_ioctl, + .read = ussl_socket_read, + .write = ussl_socket_write, + .ioctl = ussl_socket_ioctl, }; STATIC const mp_obj_type_t ussl_socket_type = { { &mp_type_type }, // Save on qstr's, reuse same as for module .name = MP_QSTR_ussl, - .print = socket_print, + .print = ussl_socket_print, .getiter = NULL, .iternext = NULL, .protocol = &ussl_socket_stream_p, @@ -260,7 +260,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); - return MP_OBJ_FROM_PTR(socket_new(sock, &args)); + return MP_OBJ_FROM_PTR(ussl_socket_new(sock, &args)); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); diff --git a/micropython/extmod/modussl_mbedtls.c b/micropython/extmod/modussl_mbedtls.c index 94863be..a71adc5 100644 --- a/micropython/extmod/modussl_mbedtls.c +++ b/micropython/extmod/modussl_mbedtls.c @@ -169,21 +169,29 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); - if (args->key.u_obj != MP_OBJ_NULL) { + if (args->key.u_obj != mp_const_none) { size_t key_len; const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len); // len should include terminating null ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0); - assert(ret == 0); + if (ret != 0) { + ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors + goto cleanup; + } size_t cert_len; const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len); // len should include terminating null ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1); - assert(ret == 0); + if (ret != 0) { + ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; // use general error for all cert errors + goto cleanup; + } ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey); - assert(ret == 0); + if (ret != 0) { + goto cleanup; + } } if (args->do_handshake.u_bool) { @@ -208,6 +216,10 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_OSError(MP_ENOMEM); + } else if (ret == MBEDTLS_ERR_PK_BAD_INPUT_DATA) { + mp_raise_ValueError("invalid key"); + } else if (ret == MBEDTLS_ERR_X509_BAD_INPUT_DATA) { + mp_raise_ValueError("invalid cert"); } else { mp_raise_OSError(MP_EIO); } @@ -219,6 +231,9 @@ STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) { mp_raise_NotImplementedError(NULL); } const mbedtls_x509_crt* peer_cert = mbedtls_ssl_get_peer_cert(&o->ssl); + if (peer_cert == NULL) { + return mp_const_none; + } return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert); @@ -331,10 +346,10 @@ STATIC const mp_obj_type_t ussl_socket_type = { STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { // TODO: Implement more args static const mp_arg_t allowed_args[] = { - { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; diff --git a/micropython/extmod/modutimeq.c b/micropython/extmod/modutimeq.c index 26f5a78..0183a0f 100644 --- a/micropython/extmod/modutimeq.c +++ b/micropython/extmod/modutimeq.c @@ -55,7 +55,7 @@ typedef struct _mp_obj_utimeq_t { STATIC mp_uint_t utimeq_id; -STATIC mp_obj_utimeq_t *get_heap(mp_obj_t heap_in) { +STATIC mp_obj_utimeq_t *utimeq_get_heap(mp_obj_t heap_in) { return MP_OBJ_TO_PTR(heap_in); } @@ -85,7 +85,7 @@ STATIC mp_obj_t utimeq_make_new(const mp_obj_type_t *type, size_t n_args, size_t return MP_OBJ_FROM_PTR(o); } -STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) { +STATIC void utimeq_heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) { struct qentry item = heap->items[pos]; while (pos > start_pos) { mp_uint_t parent_pos = (pos - 1) >> 1; @@ -101,7 +101,7 @@ STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t heap->items[pos] = item; } -STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) { +STATIC void utimeq_heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) { mp_uint_t start_pos = pos; mp_uint_t end_pos = heap->len; struct qentry item = heap->items[pos]; @@ -118,13 +118,13 @@ STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) { pos = child_pos; } heap->items[pos] = item; - heap_siftdown(heap, start_pos, pos); + utimeq_heap_siftdown(heap, start_pos, pos); } STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) { (void)n_args; mp_obj_t heap_in = args[0]; - mp_obj_utimeq_t *heap = get_heap(heap_in); + mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == heap->alloc) { mp_raise_msg(&mp_type_IndexError, "queue overflow"); } @@ -133,16 +133,16 @@ STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) { heap->items[l].id = utimeq_id++; heap->items[l].callback = args[2]; heap->items[l].args = args[3]; - heap_siftdown(heap, 0, heap->len); + utimeq_heap_siftdown(heap, 0, heap->len); heap->len++; return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_utimeq_heappush); STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) { - mp_obj_utimeq_t *heap = get_heap(heap_in); + mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); + mp_raise_msg(&mp_type_IndexError, "empty heap"); } mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref); if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) { @@ -158,16 +158,16 @@ STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) { heap->items[heap->len].callback = MP_OBJ_NULL; // so we don't retain a pointer heap->items[heap->len].args = MP_OBJ_NULL; if (heap->len) { - heap_siftup(heap, 0); + utimeq_heap_siftup(heap, 0); } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop); STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) { - mp_obj_utimeq_t *heap = get_heap(heap_in); + mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); if (heap->len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); + mp_raise_msg(&mp_type_IndexError, "empty heap"); } struct qentry *item = &heap->items[0]; @@ -177,7 +177,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_peektime_obj, mod_utimeq_peektime); #if DEBUG STATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) { - mp_obj_utimeq_t *heap = get_heap(heap_in); + mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); for (int i = 0; i < heap->len; i++) { printf(UINT_FMT "\t%p\t%p\n", heap->items[i].time, MP_OBJ_TO_PTR(heap->items[i].callback), MP_OBJ_TO_PTR(heap->items[i].args)); diff --git a/micropython/extmod/moduwebsocket.c b/micropython/extmod/moduwebsocket.c index eb5e20c..d90ee49 100644 --- a/micropython/extmod/moduwebsocket.c +++ b/micropython/extmod/moduwebsocket.c @@ -194,7 +194,7 @@ STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int if (last_state == CONTROL) { byte frame_type = self->last_flags & FRAME_OPCODE_MASK; if (frame_type == FRAME_CLOSE) { - static char close_resp[2] = {0x88, 0}; + static const char close_resp[2] = {0x88, 0}; int err; websocket_write(self_in, close_resp, sizeof(close_resp), &err); return 0; diff --git a/micropython/extmod/moduzlib.c b/micropython/extmod/moduzlib.c index f8452c7..64327f1 100644 --- a/micropython/extmod/moduzlib.c +++ b/micropython/extmod/moduzlib.c @@ -122,6 +122,7 @@ STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *er return o->decomp.dest - (byte*)buf; } +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, @@ -129,11 +130,13 @@ STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = { }; STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table); +#endif STATIC const mp_stream_p_t decompio_stream_p = { .read = decompio_read, }; +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_obj_type_t decompio_type = { { &mp_type_type }, .name = MP_QSTR_DecompIO, @@ -141,6 +144,7 @@ STATIC const mp_obj_type_t decompio_type = { .protocol = &decompio_stream_p, .locals_dict = (void*)&decompio_locals_dict, }; +#endif STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { mp_obj_t data = args[0]; @@ -201,6 +205,7 @@ STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress); +#if !MICROPY_ENABLE_DYNRUNTIME STATIC const mp_rom_map_elem_t mp_module_uzlib_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) }, { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&mod_uzlib_decompress_obj) }, @@ -213,6 +218,7 @@ const mp_obj_module_t mp_module_uzlib = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_uzlib_globals, }; +#endif // Source files #include'd here to make sure they're compiled in // only if module is enabled by config setting. diff --git a/micropython/extmod/modwebrepl.c b/micropython/extmod/modwebrepl.c index c9ef774..c92d1dc 100644 --- a/micropython/extmod/modwebrepl.c +++ b/micropython/extmod/modwebrepl.c @@ -67,10 +67,9 @@ typedef struct _mp_obj_webrepl_t { mp_obj_t cur_file; } mp_obj_webrepl_t; -// These get passed to functions which aren't force-l32, so can't be const -STATIC char passwd_prompt[] = "Password: "; -STATIC char connected_prompt[] = "\r\nWebREPL connected\r\n>>> "; -STATIC char denied_prompt[] = "\r\nAccess denied\r\n"; +STATIC const char passwd_prompt[] = "Password: "; +STATIC const char connected_prompt[] = "\r\nWebREPL connected\r\n>>> "; +STATIC const char denied_prompt[] = "\r\nAccess denied\r\n"; STATIC char webrepl_passwd[10]; @@ -138,7 +137,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) { switch (self->hdr.type) { case GET_VER: { - static char ver[] = {MICROPY_VERSION_MAJOR, MICROPY_VERSION_MINOR, MICROPY_VERSION_MICRO}; + static const char ver[] = {MICROPY_VERSION_MAJOR, MICROPY_VERSION_MINOR, MICROPY_VERSION_MICRO}; write_webrepl(self->sock, ver, sizeof(ver)); self->hdr_to_recv = sizeof(struct webrepl_file); return; @@ -246,7 +245,11 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int } if (self->data_to_recv != 0) { - static byte filebuf[512]; + // Ports that don't have much available stack can make this filebuf static + #if MICROPY_PY_WEBREPL_STATIC_FILEBUF + static + #endif + byte filebuf[512]; filebuf[0] = *(byte*)buf; mp_uint_t buf_sz = 1; if (--self->data_to_recv != 0) { diff --git a/micropython/extmod/re1.5/compilecode.c b/micropython/extmod/re1.5/compilecode.c index a685a50..3f54b39 100644 --- a/micropython/extmod/re1.5/compilecode.c +++ b/micropython/extmod/re1.5/compilecode.c @@ -53,6 +53,9 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) PC++; // Skip # of pair byte prog->len++; for (cnt = 0; *re != ']'; re++, cnt++) { + if (*re == '\\') { + ++re; + } if (!*re) return NULL; EMIT(PC++, *re); if (re[1] == '-' && re[2] != ']') { diff --git a/micropython/extmod/uos_dupterm.c b/micropython/extmod/uos_dupterm.c index 42cb214..9a8f0af 100644 --- a/micropython/extmod/uos_dupterm.c +++ b/micropython/extmod/uos_dupterm.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2016 Paul Sokolovsky - * Copyright (c) 2017 Damien P. George + * Copyright (c) 2017-2019 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -53,6 +53,45 @@ void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) { } } +uintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags) { + uintptr_t poll_flags_out = 0; + + for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { + mp_obj_t s = MP_STATE_VM(dupterm_objs[idx]); + if (s == MP_OBJ_NULL) { + continue; + } + + int errcode = 0; + mp_uint_t ret = 0; + const mp_stream_p_t *stream_p = mp_get_stream(s); + #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM + if (mp_uos_dupterm_is_builtin_stream(s)) { + ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode); + } else + #endif + { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode); + nlr_pop(); + } else { + // Ignore error with ioctl + } + } + + if (ret != MP_STREAM_ERROR) { + poll_flags_out |= ret; + if (poll_flags_out == poll_flags) { + // Finish early if all requested flags are set + break; + } + } + } + + return poll_flags_out; +} + int mp_uos_dupterm_rx_chr(void) { for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) { diff --git a/micropython/extmod/vfs.c b/micropython/extmod/vfs.c index f99be30..5f5fc63 100644 --- a/micropython/extmod/vfs.c +++ b/micropython/extmod/vfs.c @@ -38,6 +38,10 @@ #include "extmod/vfs_fat.h" #endif +#if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2 +#include "extmod/vfs_lfs.h" +#endif + #if MICROPY_VFS_POSIX #include "extmod/vfs_posix.h" #endif @@ -156,6 +160,44 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) { } } +STATIC mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) { + #if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2 + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t vfs = MP_OBJ_NULL; + mp_vfs_blockdev_t blockdev; + mp_vfs_blockdev_init(&blockdev, bdev_obj); + uint8_t buf[44]; + mp_vfs_blockdev_read_ext(&blockdev, 0, 8, sizeof(buf), buf); + #if MICROPY_VFS_LFS1 + if (memcmp(&buf[32], "littlefs", 8) == 0) { + // LFS1 + vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, 0, &bdev_obj); + nlr_pop(); + return vfs; + } + #endif + #if MICROPY_VFS_LFS2 + if (memcmp(&buf[0], "littlefs", 8) == 0) { + // LFS2 + vfs = mp_type_vfs_lfs2.make_new(&mp_type_vfs_lfs2, 1, 0, &bdev_obj); + nlr_pop(); + return vfs; + } + #endif + nlr_pop(); + } else { + // Ignore exception (eg block device doesn't support extended readblocks) + } + #endif + + #if MICROPY_VFS_FAT + return mp_fat_vfs_type.make_new(&mp_fat_vfs_type, 1, 0, &bdev_obj); + #endif + + return bdev_obj; +} + mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_readonly, ARG_mkfs }; static const mp_arg_t allowed_args[] = { @@ -178,10 +220,7 @@ mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args if (dest[0] == MP_OBJ_NULL) { // Input object has no mount method, assume it's a block device and try to // auto-detect the filesystem and create the corresponding VFS entity. - // (At the moment we only support FAT filesystems.) - #if MICROPY_VFS_FAT - vfs_obj = mp_fat_vfs_type.make_new(&mp_fat_vfs_type, 1, 0, &vfs_obj); - #endif + vfs_obj = mp_vfs_autodetect(vfs_obj); } // create new object diff --git a/micropython/extmod/vfs.h b/micropython/extmod/vfs.h index 730dea0..004b002 100644 --- a/micropython/extmod/vfs.h +++ b/micropython/extmod/vfs.h @@ -38,18 +38,40 @@ #define MP_S_IFDIR (0x4000) #define MP_S_IFREG (0x8000) +// these are the values for mp_vfs_blockdev_t.flags +#define MP_BLOCKDEV_FLAG_NATIVE (0x0001) // readblocks[2]/writeblocks[2] contain native func +#define MP_BLOCKDEV_FLAG_FREE_OBJ (0x0002) // fs_user_mount_t obj should be freed on umount +#define MP_BLOCKDEV_FLAG_HAVE_IOCTL (0x0004) // new protocol with ioctl +#define MP_BLOCKDEV_FLAG_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it + // constants for block protocol ioctl -#define BP_IOCTL_INIT (1) -#define BP_IOCTL_DEINIT (2) -#define BP_IOCTL_SYNC (3) -#define BP_IOCTL_SEC_COUNT (4) -#define BP_IOCTL_SEC_SIZE (5) +#define MP_BLOCKDEV_IOCTL_INIT (1) +#define MP_BLOCKDEV_IOCTL_DEINIT (2) +#define MP_BLOCKDEV_IOCTL_SYNC (3) +#define MP_BLOCKDEV_IOCTL_BLOCK_COUNT (4) +#define MP_BLOCKDEV_IOCTL_BLOCK_SIZE (5) +#define MP_BLOCKDEV_IOCTL_BLOCK_ERASE (6) // At the moment the VFS protocol just has import_stat, but could be extended to other methods typedef struct _mp_vfs_proto_t { mp_import_stat_t (*import_stat)(void *self, const char *path); } mp_vfs_proto_t; +typedef struct _mp_vfs_blockdev_t { + uint16_t flags; + size_t block_size; + mp_obj_t readblocks[5]; + mp_obj_t writeblocks[5]; + // new protocol uses just ioctl, old uses sync (optional) and count + union { + mp_obj_t ioctl[4]; + struct { + mp_obj_t sync[2]; + mp_obj_t count[2]; + } old; + } u; +} mp_vfs_blockdev_t; + typedef struct _mp_vfs_mount_t { const char *str; // mount point with leading / size_t len; @@ -57,6 +79,13 @@ typedef struct _mp_vfs_mount_t { struct _mp_vfs_mount_t *next; } mp_vfs_mount_t; +void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev); +int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf); +int mp_vfs_blockdev_read_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, uint8_t *buf); +int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, const uint8_t *buf); +int mp_vfs_blockdev_write_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, const uint8_t *buf); +mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg); + mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out); mp_import_stat_t mp_vfs_import_stat(const char *path); mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); diff --git a/micropython/extmod/vfs_fat.c b/micropython/extmod/vfs_fat.c index ec7aaed..f8cb1f5 100644 --- a/micropython/extmod/vfs_fat.c +++ b/micropython/extmod/vfs_fat.c @@ -68,27 +68,18 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_ // create new object fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t); vfs->base.type = type; - vfs->flags = FSUSER_FREE_OBJ; vfs->fatfs.drv = vfs; - // load block protocol methods - mp_load_method(args[0], MP_QSTR_readblocks, vfs->readblocks); - mp_load_method_maybe(args[0], MP_QSTR_writeblocks, vfs->writeblocks); - mp_load_method_maybe(args[0], MP_QSTR_ioctl, vfs->u.ioctl); - if (vfs->u.ioctl[0] != MP_OBJ_NULL) { - // device supports new block protocol, so indicate it - vfs->flags |= FSUSER_HAVE_IOCTL; - } else { - // no ioctl method, so assume the device uses the old block protocol - mp_load_method_maybe(args[0], MP_QSTR_sync, vfs->u.old.sync); - mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count); - } + // Initialise underlying block device + vfs->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ; + vfs->blockdev.block_size = FF_MIN_SS; // default, will be populated by call to MP_BLOCKDEV_IOCTL_BLOCK_SIZE + mp_vfs_blockdev_init(&vfs->blockdev, args[0]); // mount the block device so the VFS methods can be used FRESULT res = f_mount(&vfs->fatfs); if (res == FR_NO_FILESYSTEM) { // don't error out if no filesystem, to let mkfs()/mount() create one if wanted - vfs->flags |= FSUSER_NO_FILESYSTEM; + vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_NO_FILESYSTEM; } else if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } @@ -380,11 +371,11 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs // 1. readonly=True keyword argument // 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already) if (mp_obj_is_true(readonly)) { - self->writeblocks[0] = MP_OBJ_NULL; + self->blockdev.writeblocks[0] = MP_OBJ_NULL; } // check if we need to make the filesystem - FRESULT res = (self->flags & FSUSER_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK; + FRESULT res = (self->blockdev.flags & MP_BLOCKDEV_FLAG_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK; if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) { uint8_t working_buf[FF_MAX_SS]; res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); @@ -392,7 +383,7 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } - self->flags &= ~FSUSER_NO_FILESYSTEM; + self->blockdev.flags &= ~MP_BLOCKDEV_FLAG_NO_FILESYSTEM; return mp_const_none; } diff --git a/micropython/extmod/vfs_fat.h b/micropython/extmod/vfs_fat.h index ba29153..83685b5 100644 --- a/micropython/extmod/vfs_fat.h +++ b/micropython/extmod/vfs_fat.h @@ -26,30 +26,13 @@ #ifndef MICROPY_INCLUDED_EXTMOD_VFS_FAT_H #define MICROPY_INCLUDED_EXTMOD_VFS_FAT_H -#include "py/lexer.h" #include "py/obj.h" #include "lib/oofatfs/ff.h" #include "extmod/vfs.h" -// these are the values for fs_user_mount_t.flags -#define FSUSER_NATIVE (0x0001) // readblocks[2]/writeblocks[2] contain native func -#define FSUSER_FREE_OBJ (0x0002) // fs_user_mount_t obj should be freed on umount -#define FSUSER_HAVE_IOCTL (0x0004) // new protocol with ioctl -#define FSUSER_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it - typedef struct _fs_user_mount_t { mp_obj_base_t base; - uint16_t flags; - mp_obj_t readblocks[4]; - mp_obj_t writeblocks[4]; - // new protocol uses just ioctl, old uses sync (optional) and count - union { - mp_obj_t ioctl[4]; - struct { - mp_obj_t sync[2]; - mp_obj_t count[2]; - } old; - } u; + mp_vfs_blockdev_t blockdev; FATFS fatfs; } fs_user_mount_t; diff --git a/micropython/extmod/vfs_fat_diskio.c b/micropython/extmod/vfs_fat_diskio.c index e80d612..76a918f 100644 --- a/micropython/extmod/vfs_fat_diskio.c +++ b/micropython/extmod/vfs_fat_diskio.c @@ -38,16 +38,11 @@ #include "py/runtime.h" #include "py/binary.h" #include "py/objarray.h" +#include "py/mperrno.h" #include "lib/oofatfs/ff.h" #include "lib/oofatfs/diskio.h" #include "extmod/vfs_fat.h" -#if FF_MAX_SS == FF_MIN_SS -#define SECSIZE(fs) (FF_MIN_SS) -#else -#define SECSIZE(fs) ((fs)->ssize) -#endif - typedef void *bdev_t; STATIC fs_user_mount_t *disk_get_device(void *bdev) { return (fs_user_mount_t*)bdev; @@ -69,20 +64,9 @@ DRESULT disk_read ( return RES_PARERR; } - if (vfs->flags & FSUSER_NATIVE) { - mp_uint_t (*f)(uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->readblocks[2]; - if (f(buff, sector, count) != 0) { - return RES_ERROR; - } - } else { - mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), buff}; - vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - vfs->readblocks[3] = MP_OBJ_FROM_PTR(&ar); - mp_call_method_n_kw(2, 0, vfs->readblocks); - // TODO handle error return - } + int ret = mp_vfs_blockdev_read(&vfs->blockdev, sector, count, buff); - return RES_OK; + return ret == 0 ? RES_OK : RES_ERROR; } /*-----------------------------------------------------------------------*/ @@ -101,25 +85,14 @@ DRESULT disk_write ( return RES_PARERR; } - if (vfs->writeblocks[0] == MP_OBJ_NULL) { + int ret = mp_vfs_blockdev_write(&vfs->blockdev, sector, count, buff); + + if (ret == -MP_EROFS) { // read-only block device return RES_WRPRT; } - if (vfs->flags & FSUSER_NATIVE) { - mp_uint_t (*f)(const uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->writeblocks[2]; - if (f(buff, sector, count) != 0) { - return RES_ERROR; - } - } else { - mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), (void*)buff}; - vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - vfs->writeblocks[3] = MP_OBJ_FROM_PTR(&ar); - mp_call_method_n_kw(2, 0, vfs->writeblocks); - // TODO handle error return - } - - return RES_OK; + return ret == 0 ? RES_OK : RES_ERROR; } @@ -139,42 +112,16 @@ DRESULT disk_ioctl ( } // First part: call the relevant method of the underlying block device + static const uint8_t op_map[8] = { + [CTRL_SYNC] = MP_BLOCKDEV_IOCTL_SYNC, + [GET_SECTOR_COUNT] = MP_BLOCKDEV_IOCTL_BLOCK_COUNT, + [GET_SECTOR_SIZE] = MP_BLOCKDEV_IOCTL_BLOCK_SIZE, + [IOCTL_INIT] = MP_BLOCKDEV_IOCTL_INIT, + }; + uint8_t bp_op = op_map[cmd & 7]; mp_obj_t ret = mp_const_none; - if (vfs->flags & FSUSER_HAVE_IOCTL) { - // new protocol with ioctl - static const uint8_t op_map[8] = { - [CTRL_SYNC] = BP_IOCTL_SYNC, - [GET_SECTOR_COUNT] = BP_IOCTL_SEC_COUNT, - [GET_SECTOR_SIZE] = BP_IOCTL_SEC_SIZE, - [IOCTL_INIT] = BP_IOCTL_INIT, - }; - uint8_t bp_op = op_map[cmd & 7]; - if (bp_op != 0) { - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); - } - } else { - // old protocol with sync and count - switch (cmd) { - case CTRL_SYNC: - if (vfs->u.old.sync[0] != MP_OBJ_NULL) { - mp_call_method_n_kw(0, 0, vfs->u.old.sync); - } - break; - - case GET_SECTOR_COUNT: - ret = mp_call_method_n_kw(0, 0, vfs->u.old.count); - break; - - case GET_SECTOR_SIZE: - // old protocol has fixed sector size of 512 bytes - break; - - case IOCTL_INIT: - // old protocol doesn't have init - break; - } + if (bp_op != 0) { + ret = mp_vfs_blockdev_ioctl(&vfs->blockdev, bp_op, 0); } // Second part: convert the result for return @@ -194,10 +141,8 @@ DRESULT disk_ioctl ( } else { *((WORD*)buff) = mp_obj_get_int(ret); } - #if FF_MAX_SS != FF_MIN_SS // need to store ssize because we use it in disk_read/disk_write - vfs->fatfs.ssize = *((WORD*)buff); - #endif + vfs->blockdev.block_size = *((WORD*)buff); return RES_OK; } @@ -211,7 +156,7 @@ DRESULT disk_ioctl ( if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) { // error initialising stat = STA_NOINIT; - } else if (vfs->writeblocks[0] == MP_OBJ_NULL) { + } else if (vfs->blockdev.writeblocks[0] == MP_OBJ_NULL) { stat = STA_PROTECT; } else { stat = 0; diff --git a/micropython/extmod/vfs_fat_file.c b/micropython/extmod/vfs_fat_file.c index f7b9331..fb1e582 100644 --- a/micropython/extmod/vfs_fat_file.c +++ b/micropython/extmod/vfs_fat_file.c @@ -219,7 +219,7 @@ STATIC mp_obj_t file_obj_make_new(const mp_obj_type_t *type, size_t n_args, size // TODO gc hook to close the file if not already closed -STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { +STATIC const mp_rom_map_elem_t vfs_fat_rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, @@ -234,10 +234,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) }, }; -STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(vfs_fat_rawfile_locals_dict, vfs_fat_rawfile_locals_dict_table); #if MICROPY_PY_IO_FILEIO -STATIC const mp_stream_p_t fileio_stream_p = { +STATIC const mp_stream_p_t vfs_fat_fileio_stream_p = { .read = file_obj_read, .write = file_obj_write, .ioctl = file_obj_ioctl, @@ -250,12 +250,12 @@ const mp_obj_type_t mp_type_vfs_fat_fileio = { .make_new = file_obj_make_new, .getiter = mp_identity_getiter, .iternext = mp_stream_unbuffered_iter, - .protocol = &fileio_stream_p, - .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, + .protocol = &vfs_fat_fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&vfs_fat_rawfile_locals_dict, }; #endif -STATIC const mp_stream_p_t textio_stream_p = { +STATIC const mp_stream_p_t vfs_fat_textio_stream_p = { .read = file_obj_read, .write = file_obj_write, .ioctl = file_obj_ioctl, @@ -269,8 +269,8 @@ const mp_obj_type_t mp_type_vfs_fat_textio = { .make_new = file_obj_make_new, .getiter = mp_identity_getiter, .iternext = mp_stream_unbuffered_iter, - .protocol = &textio_stream_p, - .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, + .protocol = &vfs_fat_textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&vfs_fat_rawfile_locals_dict, }; // Factory function for I/O stream classes diff --git a/micropython/extmod/vfs_posix.c b/micropython/extmod/vfs_posix.c index 4ef7619..d943e0c 100644 --- a/micropython/extmod/vfs_posix.c +++ b/micropython/extmod/vfs_posix.c @@ -31,6 +31,7 @@ #if MICROPY_VFS_POSIX +#include #include #include #include diff --git a/micropython/extmod/vfs_posix_file.c b/micropython/extmod/vfs_posix_file.c index 44cb85d..30fde81 100644 --- a/micropython/extmod/vfs_posix_file.c +++ b/micropython/extmod/vfs_posix_file.c @@ -44,7 +44,7 @@ typedef struct _mp_obj_vfs_posix_file_t { #ifdef MICROPY_CPYTHON_COMPAT STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) { if (o->fd < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file")); + mp_raise_msg(&mp_type_ValueError, "I/O operation on closed file"); } } #else @@ -200,7 +200,7 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ } } -STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { +STATIC const mp_rom_map_elem_t vfs_posix_rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&vfs_posix_file_fileno_obj) }, { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, @@ -215,10 +215,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) }, }; -STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(vfs_posix_rawfile_locals_dict, vfs_posix_rawfile_locals_dict_table); #if MICROPY_PY_IO_FILEIO -STATIC const mp_stream_p_t fileio_stream_p = { +STATIC const mp_stream_p_t vfs_posix_fileio_stream_p = { .read = vfs_posix_file_read, .write = vfs_posix_file_write, .ioctl = vfs_posix_file_ioctl, @@ -231,12 +231,12 @@ const mp_obj_type_t mp_type_vfs_posix_fileio = { .make_new = vfs_posix_file_make_new, .getiter = mp_identity_getiter, .iternext = mp_stream_unbuffered_iter, - .protocol = &fileio_stream_p, - .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, + .protocol = &vfs_posix_fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&vfs_posix_rawfile_locals_dict, }; #endif -STATIC const mp_stream_p_t textio_stream_p = { +STATIC const mp_stream_p_t vfs_posix_textio_stream_p = { .read = vfs_posix_file_read, .write = vfs_posix_file_write, .ioctl = vfs_posix_file_ioctl, @@ -250,8 +250,8 @@ const mp_obj_type_t mp_type_vfs_posix_textio = { .make_new = vfs_posix_file_make_new, .getiter = mp_identity_getiter, .iternext = mp_stream_unbuffered_iter, - .protocol = &textio_stream_p, - .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, + .protocol = &vfs_posix_textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&vfs_posix_rawfile_locals_dict, }; const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILENO}; diff --git a/micropython/lib/utils/pyexec.c b/micropython/lib/utils/pyexec.c index 022e122..035e934 100644 --- a/micropython/lib/utils/pyexec.c +++ b/micropython/lib/utils/pyexec.c @@ -90,7 +90,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input // source is a lexer, parse and compile the script qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); - module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL); + module_fun = mp_compile(&parse_tree, source_name, exec_flags & EXEC_FLAG_IS_REPL); #else mp_raise_msg(&mp_type_RuntimeError, "script compilation not supported"); #endif diff --git a/micropython/lib/utils/sys_stdio_mphal.c b/micropython/lib/utils/sys_stdio_mphal.c index 234db08..3fcaf8e 100644 --- a/micropython/lib/utils/sys_stdio_mphal.c +++ b/micropython/lib/utils/sys_stdio_mphal.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013-2017 Damien P. George + * Copyright (c) 2013-2019 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -85,6 +85,16 @@ STATIC mp_uint_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, } } +STATIC mp_uint_t stdio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)self_in; + if (request == MP_STREAM_POLL) { + return mp_hal_stdio_poll(arg); + } else { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + STATIC mp_obj_t stdio_obj___exit__(size_t n_args, const mp_obj_t *args) { return mp_const_none; } @@ -112,6 +122,7 @@ STATIC MP_DEFINE_CONST_DICT(stdio_locals_dict, stdio_locals_dict_table); STATIC const mp_stream_p_t stdio_obj_stream_p = { .read = stdio_read, .write = stdio_write, + .ioctl = stdio_ioctl, .is_text = true, }; @@ -146,6 +157,7 @@ STATIC mp_uint_t stdio_buffer_write(mp_obj_t self_in, const void *buf, mp_uint_t STATIC const mp_stream_p_t stdio_buffer_obj_stream_p = { .read = stdio_buffer_read, .write = stdio_buffer_write, + .ioctl = stdio_ioctl, .is_text = false, }; diff --git a/micropython/micropython b/micropython/micropython new file mode 120000 index 0000000..2f78585 --- /dev/null +++ b/micropython/micropython @@ -0,0 +1 @@ +micropython \ No newline at end of file diff --git a/micropython/mpy-cross/main.c b/micropython/mpy-cross/main.c index 970ad2d..e822772 100644 --- a/micropython/mpy-cross/main.c +++ b/micropython/mpy-cross/main.c @@ -72,7 +72,7 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha #endif mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, emit_opt, false); + mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, false); vstr_t vstr; vstr_init(&vstr, 16); @@ -109,13 +109,17 @@ STATIC int usage(char **argv) { "-msmall-int-bits=number : set the maximum bits used to encode a small-int\n" "-mno-unicode : don't support unicode in compiled strings\n" "-mcache-lookup-bc : cache map lookups in the bytecode\n" -"-march= : set architecture for native emitter; x86, x64, armv6, armv7m, xtensa\n" +"-march= : set architecture for native emitter; x86, x64, armv6, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin\n" "\n" "Implementation specific options:\n", argv[0] ); int impl_opts_cnt = 0; printf( +#if MICROPY_EMIT_NATIVE " emit={bytecode,native,viper} -- set the default code emitter\n" +#else +" emit=bytecode -- set the default code emitter\n" +#endif ); impl_opts_cnt++; printf( @@ -140,10 +144,12 @@ STATIC void pre_process_options(int argc, char **argv) { } if (strcmp(argv[a + 1], "emit=bytecode") == 0) { emit_opt = MP_EMIT_OPT_BYTECODE; + #if MICROPY_EMIT_NATIVE } else if (strcmp(argv[a + 1], "emit=native") == 0) { emit_opt = MP_EMIT_OPT_NATIVE_PYTHON; } else if (strcmp(argv[a + 1], "emit=viper") == 0) { emit_opt = MP_EMIT_OPT_VIPER; + #endif } else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) { char *end; heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, &end, 0); @@ -190,18 +196,29 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_obj_list_init(mp_sys_path, 0); mp_obj_list_init(mp_sys_argv, 0); + #if MICROPY_EMIT_NATIVE + // Set default emitter options + MP_STATE_VM(default_emit_opt) = emit_opt; + #else + (void)emit_opt; + #endif + // set default compiler configuration mp_dynamic_compiler.small_int_bits = 31; mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0; mp_dynamic_compiler.py_builtins_str_unicode = 1; #if defined(__i386__) mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_X86; #elif defined(__x86_64__) mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64; + mp_dynamic_compiler.nlr_buf_num_regs = MAX(MICROPY_NLR_NUM_REGS_X64, MICROPY_NLR_NUM_REGS_X64_WIN); #elif defined(__arm__) && !defined(__thumb2__) mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; #else mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_NONE; + mp_dynamic_compiler.nlr_buf_num_regs = 0; #endif const char *input_file = NULL; @@ -258,14 +275,31 @@ MP_NOINLINE int main_(int argc, char **argv) { const char *arch = argv[a] + sizeof("-march=") - 1; if (strcmp(arch, "x86") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_X86; } else if (strcmp(arch, "x64") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64; + mp_dynamic_compiler.nlr_buf_num_regs = MAX(MICROPY_NLR_NUM_REGS_X64, MICROPY_NLR_NUM_REGS_X64_WIN); } else if (strcmp(arch, "armv6") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; } else if (strcmp(arch, "armv7m") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7M; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; + } else if (strcmp(arch, "armv7em") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7EM; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; + } else if (strcmp(arch, "armv7emsp") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7EMSP; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; + } else if (strcmp(arch, "armv7emdp") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7EMDP; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; } else if (strcmp(arch, "xtensa") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSA; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSA; + } else if (strcmp(arch, "xtensawin") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSAWIN; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSAWIN; } else { return usage(argv); } diff --git a/micropython/py/asmarm.c b/micropython/py/asmarm.c index f2221f8..59c661c 100644 --- a/micropython/py/asmarm.c +++ b/micropython/py/asmarm.c @@ -40,7 +40,11 @@ void asm_arm_end_pass(asm_arm_t *as) { if (as->base.pass == MP_ASM_PASS_EMIT) { -#ifdef __arm__ +#if defined(__linux__) && defined(__GNUC__) + char *start = mp_asm_base_get_code(&as->base); + char *end = start + mp_asm_base_get_code_size(&as->base); + __builtin___clear_cache(start, end); +#elif defined(__arm__) // flush I- and D-cache asm volatile( "0:" diff --git a/micropython/py/asmbase.c b/micropython/py/asmbase.c index 4c84c3b..ab861da 100644 --- a/micropython/py/asmbase.c +++ b/micropython/py/asmbase.c @@ -31,7 +31,7 @@ #include "py/misc.h" #include "py/asmbase.h" -#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM +#if MICROPY_EMIT_MACHINE_CODE void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels) { as->max_num_labels = max_num_labels; @@ -99,4 +99,4 @@ void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val) { } } -#endif // MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM +#endif // MICROPY_EMIT_MACHINE_CODE diff --git a/micropython/py/asmbase.h b/micropython/py/asmbase.h index d2b4038..b5e2593 100644 --- a/micropython/py/asmbase.h +++ b/micropython/py/asmbase.h @@ -60,7 +60,7 @@ static inline size_t mp_asm_base_get_code_size(mp_asm_base_t *as) { static inline void *mp_asm_base_get_code(mp_asm_base_t *as) { #if defined(MP_PLAT_COMMIT_EXEC) - return MP_PLAT_COMMIT_EXEC(as->code_base, as->code_size); + return MP_PLAT_COMMIT_EXEC(as->code_base, as->code_size, NULL); #else return as->code_base; #endif diff --git a/micropython/py/asmxtensa.c b/micropython/py/asmxtensa.c index a269e5e..32e5e95 100644 --- a/micropython/py/asmxtensa.c +++ b/micropython/py/asmxtensa.c @@ -30,14 +30,13 @@ #include "py/mpconfig.h" // wrapper around everything in this file -#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA +#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN #include "py/asmxtensa.h" #define WORD_SIZE (4) #define SIGNED_FIT8(x) ((((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)) #define SIGNED_FIT12(x) ((((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)) -#define NUM_REGS_SAVED (5) void asm_xtensa_end_pass(asm_xtensa_t *as) { as->num_const = as->cur_const; @@ -69,7 +68,7 @@ void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) { as->const_table = (uint32_t*)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); // adjust the stack-pointer to store a0, a12, a13, a14, a15 and locals, 16-byte aligned - as->stack_adjust = (((NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15; + as->stack_adjust = (((ASM_XTENSA_NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15; if (SIGNED_FIT8(-as->stack_adjust)) { asm_xtensa_op_addi(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, -as->stack_adjust); } else { @@ -79,14 +78,14 @@ void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) { // save return value (a0) and callee-save registers (a12, a13, a14, a15) asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); - for (int i = 1; i < NUM_REGS_SAVED; ++i) { + for (int i = 1; i < ASM_XTENSA_NUM_REGS_SAVED; ++i) { asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A11 + i, ASM_XTENSA_REG_A1, i); } } void asm_xtensa_exit(asm_xtensa_t *as) { // restore registers - for (int i = NUM_REGS_SAVED - 1; i >= 1; --i) { + for (int i = ASM_XTENSA_NUM_REGS_SAVED - 1; i >= 1; --i) { asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A11 + i, ASM_XTENSA_REG_A1, i); } asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); @@ -102,6 +101,22 @@ void asm_xtensa_exit(asm_xtensa_t *as) { asm_xtensa_op_ret_n(as); } +void asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals) { + // jump over the constants + asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4); + mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte + as->const_table = (uint32_t*)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); + + as->stack_adjust = 32 + ((((ASM_XTENSA_NUM_REGS_SAVED_WIN + num_locals) * WORD_SIZE) + 15) & ~15); + asm_xtensa_op_entry(as, ASM_XTENSA_REG_A1, as->stack_adjust); + asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); +} + +void asm_xtensa_exit_win(asm_xtensa_t *as) { + asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); + asm_xtensa_op_retw_n(as); +} + STATIC uint32_t get_label_dest(asm_xtensa_t *as, uint label) { assert(label < as->base.max_num_labels); return as->base.label_offsets[label]; @@ -178,15 +193,15 @@ void asm_xtensa_mov_reg_i32_optimised(asm_xtensa_t *as, uint reg_dest, uint32_t } void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src) { - asm_xtensa_op_s32i(as, reg_src, ASM_XTENSA_REG_A1, NUM_REGS_SAVED + local_num); + asm_xtensa_op_s32i(as, reg_src, ASM_XTENSA_REG_A1, local_num); } void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num) { - asm_xtensa_op_l32i(as, reg_dest, ASM_XTENSA_REG_A1, NUM_REGS_SAVED + local_num); + asm_xtensa_op_l32i(as, reg_dest, ASM_XTENSA_REG_A1, local_num); } void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num) { - uint off = (NUM_REGS_SAVED + local_num) * WORD_SIZE; + uint off = local_num * WORD_SIZE; if (SIGNED_FIT8(off)) { asm_xtensa_op_addi(as, reg_dest, ASM_XTENSA_REG_A1, off); } else { @@ -226,4 +241,13 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx) { asm_xtensa_op_callx0(as, ASM_XTENSA_REG_A0); } -#endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA +void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx) { + if (idx < 16) { + asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A8, ASM_XTENSA_REG_FUN_TABLE_WIN, idx); + } else { + asm_xtensa_op_l32i(as, ASM_XTENSA_REG_A8, ASM_XTENSA_REG_FUN_TABLE_WIN, idx); + } + asm_xtensa_op_callx8(as, ASM_XTENSA_REG_A8); +} + +#endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN diff --git a/micropython/py/asmxtensa.h b/micropython/py/asmxtensa.h index d95af14..5eb40da 100644 --- a/micropython/py/asmxtensa.h +++ b/micropython/py/asmxtensa.h @@ -37,6 +37,16 @@ // callee save: a1, a12, a13, a14, a15 // caller save: a3 +// With windowed registers, size 8: +// - a0: return PC +// - a1: stack pointer, full descending, aligned to 16 bytes +// - a2-a7: incoming args, and essentially callee save +// - a2: return value +// - a8-a15: caller save temporaries +// - a10-a15: input args to called function +// - a10: return value of called function +// note: a0-a7 are saved automatically via window shift of called function + #define ASM_XTENSA_REG_A0 (0) #define ASM_XTENSA_REG_A1 (1) #define ASM_XTENSA_REG_A2 (2) @@ -96,6 +106,10 @@ #define ASM_XTENSA_ENCODE_RI7(op0, s, imm7) \ ((((imm7) & 0xf) << 12) | ((s) << 8) | ((imm7) & 0x70) | (op0)) +// Number of registers saved on the stack upon entry to function +#define ASM_XTENSA_NUM_REGS_SAVED (5) +#define ASM_XTENSA_NUM_REGS_SAVED_WIN (1) + typedef struct _asm_xtensa_t { mp_asm_base_t base; uint32_t cur_const; @@ -109,11 +123,18 @@ void asm_xtensa_end_pass(asm_xtensa_t *as); void asm_xtensa_entry(asm_xtensa_t *as, int num_locals); void asm_xtensa_exit(asm_xtensa_t *as); +void asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals); +void asm_xtensa_exit_win(asm_xtensa_t *as); + void asm_xtensa_op16(asm_xtensa_t *as, uint16_t op); void asm_xtensa_op24(asm_xtensa_t *as, uint32_t op); // raw instructions +static inline void asm_xtensa_op_entry(asm_xtensa_t *as, uint reg_src, int32_t num_bytes) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_BRI12(6, reg_src, 0, 3, (num_bytes / 8) & 0xfff)); +} + static inline void asm_xtensa_op_add_n(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(10, reg_dest, reg_src_a, reg_src_b)); } @@ -142,6 +163,10 @@ static inline void asm_xtensa_op_callx0(asm_xtensa_t *as, uint reg) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 3, 0)); } +static inline void asm_xtensa_op_callx8(asm_xtensa_t *as, uint reg) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 3, 2)); +} + static inline void asm_xtensa_op_j(asm_xtensa_t *as, int32_t rel18) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALL(6, 0, rel18 & 0x3ffff)); } @@ -194,6 +219,10 @@ static inline void asm_xtensa_op_ret_n(asm_xtensa_t *as) { asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 15, 0, 0)); } +static inline void asm_xtensa_op_retw_n(asm_xtensa_t *as) { + asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 15, 0, 1)); +} + static inline void asm_xtensa_op_s8i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint byte_offset) { asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 4, reg_base, reg_src, byte_offset & 0xff)); } @@ -246,9 +275,11 @@ void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_pcrel(asm_xtensa_t *as, uint reg_dest, uint label); void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); +void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); // Holds a pointer to mp_fun_table #define ASM_XTENSA_REG_FUN_TABLE ASM_XTENSA_REG_A15 +#define ASM_XTENSA_REG_FUN_TABLE_WIN ASM_XTENSA_REG_A7 #if GENERIC_ASM_API @@ -257,6 +288,9 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); #define ASM_WORD_SIZE (4) +#if !GENERIC_ASM_API_WIN +// Configuration for non-windowed calls + #define REG_RET ASM_XTENSA_REG_A2 #define REG_ARG_1 ASM_XTENSA_REG_A2 #define REG_ARG_2 ASM_XTENSA_REG_A3 @@ -273,12 +307,47 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); #define REG_LOCAL_3 ASM_XTENSA_REG_A14 #define REG_LOCAL_NUM (3) +#define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED #define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE +#define ASM_ENTRY(as, nlocal) asm_xtensa_entry((as), (nlocal)) +#define ASM_EXIT(as) asm_xtensa_exit((as)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) + +#else +// Configuration for windowed calls with window size 8 + +#define REG_PARENT_RET ASM_XTENSA_REG_A2 +#define REG_PARENT_ARG_1 ASM_XTENSA_REG_A2 +#define REG_PARENT_ARG_2 ASM_XTENSA_REG_A3 +#define REG_PARENT_ARG_3 ASM_XTENSA_REG_A4 +#define REG_PARENT_ARG_4 ASM_XTENSA_REG_A5 +#define REG_RET ASM_XTENSA_REG_A10 +#define REG_ARG_1 ASM_XTENSA_REG_A10 +#define REG_ARG_2 ASM_XTENSA_REG_A11 +#define REG_ARG_3 ASM_XTENSA_REG_A12 +#define REG_ARG_4 ASM_XTENSA_REG_A13 + +#define REG_TEMP0 ASM_XTENSA_REG_A10 +#define REG_TEMP1 ASM_XTENSA_REG_A11 +#define REG_TEMP2 ASM_XTENSA_REG_A12 + +#define REG_LOCAL_1 ASM_XTENSA_REG_A4 +#define REG_LOCAL_2 ASM_XTENSA_REG_A5 +#define REG_LOCAL_3 ASM_XTENSA_REG_A6 +#define REG_LOCAL_NUM (3) + +#define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED_WIN +#define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE_WIN + +#define ASM_ENTRY(as, nlocal) asm_xtensa_entry_win((as), (nlocal)) +#define ASM_EXIT(as) asm_xtensa_exit_win((as)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind_win((as), (idx)) + +#endif + #define ASM_T asm_xtensa_t #define ASM_END_PASS asm_xtensa_end_pass -#define ASM_ENTRY asm_xtensa_entry -#define ASM_EXIT asm_xtensa_exit #define ASM_JUMP asm_xtensa_j_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ @@ -288,15 +357,14 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); #define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ asm_xtensa_bcc_reg_reg_label(as, ASM_XTENSA_CC_EQ, reg1, reg2, label) #define ASM_JUMP_REG(as, reg) asm_xtensa_op_jx((as), (reg)) -#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) -#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), (local_num), (reg_src)) +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), ASM_NUM_REGS_SAVED + (local_num), (reg_src)) #define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32_optimised((as), (reg_dest), (imm)) #define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) #define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) -#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), (local_num)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), ASM_NUM_REGS_SAVED + (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mov_n((as), (reg_dest), (reg_src)) -#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), (local_num)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), ASM_NUM_REGS_SAVED + (local_num)) #define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_xtensa_mov_reg_pcrel((as), (reg_dest), (label)) #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) \ diff --git a/micropython/py/bc.c b/micropython/py/bc.c index b178e7c..7dd4b22 100644 --- a/micropython/py/bc.c +++ b/micropython/py/bc.c @@ -40,6 +40,8 @@ #define DEBUG_printf(...) (void)0 #endif +#if !MICROPY_PERSISTENT_CODE + mp_uint_t mp_decode_uint(const byte **ptr) { mp_uint_t unum = 0; byte val; @@ -70,6 +72,8 @@ const byte *mp_decode_uint_skip(const byte *ptr) { return ptr; } +#endif + STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE // generic message, used also for other argument issues @@ -119,16 +123,22 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw code_state->prev = NULL; #endif - // get params - size_t n_state = mp_decode_uint(&code_state->ip); - code_state->ip = mp_decode_uint_skip(code_state->ip); // skip n_exc_stack - size_t scope_flags = *code_state->ip++; - size_t n_pos_args = *code_state->ip++; - size_t n_kwonly_args = *code_state->ip++; - size_t n_def_pos_args = *code_state->ip++; + #if MICROPY_PY_SYS_SETTRACE + code_state->prev_state = NULL; + code_state->frame = NULL; + #endif + + // Get cached n_state (rather than decode it again) + size_t n_state = code_state->n_state; + + // Decode prelude + size_t n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args; + MP_BC_PRELUDE_SIG_DECODE_INTO(code_state->ip, n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args); + (void)n_state_unused; + (void)n_exc_stack_unused; code_state->sp = &code_state->state[0] - 1; - code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1; + code_state->exc_sp_idx = 0; // zero out the local stack to begin with memset(code_state->state, 0, n_state * sizeof(*code_state->state)); @@ -263,19 +273,25 @@ continue2:; } } - // get the ip and skip argument names + // read the size part of the prelude const byte *ip = code_state->ip; + MP_BC_PRELUDE_SIZE_DECODE(ip); // jump over code info (source file and line-number mapping) - ip += mp_decode_uint_value(ip); + ip += n_info; // bytecode prelude: initialise closed over variables - size_t local_num; - while ((local_num = *ip++) != 255) { + for (; n_cell; --n_cell) { + size_t local_num = *ip++; code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]); } + #if !MICROPY_PERSISTENT_CODE + // so bytecode is aligned + ip = MP_ALIGN(ip, sizeof(mp_uint_t)); + #endif + // now that we skipped over the prelude, set the ip for the VM code_state->ip = ip; @@ -287,105 +303,17 @@ continue2:; #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE // The following table encodes the number of bytes that a specific opcode -// takes up. There are 3 special opcodes that always have an extra byte: -// MP_BC_MAKE_CLOSURE -// MP_BC_MAKE_CLOSURE_DEFARGS -// MP_BC_RAISE_VARARGS +// takes up. Some opcodes have an extra byte, defined by MP_BC_MASK_EXTRA_BYTE. // There are 4 special opcodes that have an extra byte only when // MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE is enabled (and they take a qstr): // MP_BC_LOAD_NAME // MP_BC_LOAD_GLOBAL // MP_BC_LOAD_ATTR // MP_BC_STORE_ATTR -#define OC4(a, b, c, d) (a | (b << 2) | (c << 4) | (d << 6)) -#define U (0) // undefined opcode -#define B (MP_OPCODE_BYTE) // single byte -#define Q (MP_OPCODE_QSTR) // single byte plus 2-byte qstr -#define V (MP_OPCODE_VAR_UINT) // single byte plus variable encoded unsigned int -#define O (MP_OPCODE_OFFSET) // single byte plus 2-byte bytecode offset -STATIC const byte opcode_format_table[64] = { - OC4(U, U, U, U), // 0x00-0x03 - OC4(U, U, U, U), // 0x04-0x07 - OC4(U, U, U, U), // 0x08-0x0b - OC4(U, U, U, U), // 0x0c-0x0f - OC4(B, B, B, U), // 0x10-0x13 - OC4(V, U, Q, V), // 0x14-0x17 - OC4(B, V, V, Q), // 0x18-0x1b - OC4(Q, Q, Q, Q), // 0x1c-0x1f - OC4(B, B, V, V), // 0x20-0x23 - OC4(Q, Q, Q, B), // 0x24-0x27 - OC4(V, V, Q, Q), // 0x28-0x2b - OC4(U, U, U, U), // 0x2c-0x2f - OC4(B, B, B, B), // 0x30-0x33 - OC4(B, O, O, O), // 0x34-0x37 - OC4(O, O, U, U), // 0x38-0x3b - OC4(U, O, B, O), // 0x3c-0x3f - OC4(O, B, B, O), // 0x40-0x43 - OC4(O, U, O, B), // 0x44-0x47 - OC4(U, U, U, U), // 0x48-0x4b - OC4(U, U, U, U), // 0x4c-0x4f - OC4(V, V, U, V), // 0x50-0x53 - OC4(B, U, V, V), // 0x54-0x57 - OC4(V, V, V, B), // 0x58-0x5b - OC4(B, B, B, U), // 0x5c-0x5f - OC4(V, V, V, V), // 0x60-0x63 - OC4(V, V, V, V), // 0x64-0x67 - OC4(Q, Q, B, U), // 0x68-0x6b - OC4(U, U, U, U), // 0x6c-0x6f - - OC4(B, B, B, B), // 0x70-0x73 - OC4(B, B, B, B), // 0x74-0x77 - OC4(B, B, B, B), // 0x78-0x7b - OC4(B, B, B, B), // 0x7c-0x7f - OC4(B, B, B, B), // 0x80-0x83 - OC4(B, B, B, B), // 0x84-0x87 - OC4(B, B, B, B), // 0x88-0x8b - OC4(B, B, B, B), // 0x8c-0x8f - OC4(B, B, B, B), // 0x90-0x93 - OC4(B, B, B, B), // 0x94-0x97 - OC4(B, B, B, B), // 0x98-0x9b - OC4(B, B, B, B), // 0x9c-0x9f - OC4(B, B, B, B), // 0xa0-0xa3 - OC4(B, B, B, B), // 0xa4-0xa7 - OC4(B, B, B, B), // 0xa8-0xab - OC4(B, B, B, B), // 0xac-0xaf - - OC4(B, B, B, B), // 0xb0-0xb3 - OC4(B, B, B, B), // 0xb4-0xb7 - OC4(B, B, B, B), // 0xb8-0xbb - OC4(B, B, B, B), // 0xbc-0xbf - - OC4(B, B, B, B), // 0xc0-0xc3 - OC4(B, B, B, B), // 0xc4-0xc7 - OC4(B, B, B, B), // 0xc8-0xcb - OC4(B, B, B, B), // 0xcc-0xcf - - OC4(B, B, B, B), // 0xd0-0xd3 - OC4(U, U, U, B), // 0xd4-0xd7 - OC4(B, B, B, B), // 0xd8-0xdb - OC4(B, B, B, B), // 0xdc-0xdf - - OC4(B, B, B, B), // 0xe0-0xe3 - OC4(B, B, B, B), // 0xe4-0xe7 - OC4(B, B, B, B), // 0xe8-0xeb - OC4(B, B, B, B), // 0xec-0xef - - OC4(B, B, B, B), // 0xf0-0xf3 - OC4(B, B, B, B), // 0xf4-0xf7 - OC4(U, U, U, U), // 0xf8-0xfb - OC4(U, U, U, U), // 0xfc-0xff -}; -#undef OC4 -#undef U -#undef B -#undef Q -#undef V -#undef O - uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) { - uint f = (opcode_format_table[*ip >> 2] >> (2 * (*ip & 3))) & 3; + uint f = MP_BC_FORMAT(*ip); const byte *ip_start = ip; - if (f == MP_OPCODE_QSTR) { + if (f == MP_BC_FORMAT_QSTR) { if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { if (*ip == MP_BC_LOAD_NAME || *ip == MP_BC_LOAD_GLOBAL @@ -396,18 +324,14 @@ uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) } ip += 3; } else { - int extra_byte = ( - *ip == MP_BC_RAISE_VARARGS - || *ip == MP_BC_MAKE_CLOSURE - || *ip == MP_BC_MAKE_CLOSURE_DEFARGS - ); + int extra_byte = (*ip & MP_BC_MASK_EXTRA_BYTE) == 0; ip += 1; - if (f == MP_OPCODE_VAR_UINT) { + if (f == MP_BC_FORMAT_VAR_UINT) { if (count_var_uint) { while ((*ip++ & 0x80) != 0) { } } - } else if (f == MP_OPCODE_OFFSET) { + } else if (f == MP_BC_FORMAT_OFFSET) { ip += 2; } ip += extra_byte; diff --git a/micropython/py/bc.h b/micropython/py/bc.h index 0aadfa8..a96d17a 100644 --- a/micropython/py/bc.h +++ b/micropython/py/bc.h @@ -32,24 +32,35 @@ // bytecode layout: // -// n_state : var uint -// n_exc_stack : var uint -// scope_flags : byte -// n_pos_args : byte number of arguments this function takes -// n_kwonly_args : byte number of keyword-only arguments this function takes -// n_def_pos_args : byte number of default positional arguments +// func signature : var uint +// contains six values interleaved bit-wise as: xSSSSEAA [xFSSKAED repeated] +// x = extension another byte follows +// S = n_state - 1 number of entries in Python value stack +// E = n_exc_stack number of entries in exception stack +// F = scope_flags four bits of flags, MP_SCOPE_FLAG_xxx +// A = n_pos_args number of arguments this function takes +// K = n_kwonly_args number of keyword-only arguments this function takes +// D = n_def_pos_args number of default positional arguments // -// code_info_size : var uint | code_info_size counts bytes in this chunk -// simple_name : var qstr | -// source_file : var qstr | -// | -// | only needed if bytecode contains pointers +// prelude size : var uint +// contains two values interleaved bit-wise as: xIIIIIIC repeated +// x = extension another byte follows +// I = n_info number of bytes in source info section +// C = n_cells number of bytes/cells in closure section // -// local_num0 : byte | -// ... : byte | -// local_numN : byte | N = num_cells -// 255 : byte | end of list sentinel -// | +// source info section: +// simple_name : var qstr +// source_file : var qstr +// +// +// closure section: +// local_num0 : byte +// ... : byte +// local_numN : byte N = n_cells-1 +// +// only needed if bytecode contains pointers +// +// // // // constant table layout: @@ -60,13 +71,127 @@ // const0 : obj // constN : obj +#define MP_BC_PRELUDE_SIG_ENCODE(S, E, scope, out_byte, out_env) \ +do { \ + /*// Get values to store in prelude */ \ + size_t F = scope->scope_flags & MP_SCOPE_FLAG_ALL_SIG; \ + size_t A = scope->num_pos_args; \ + size_t K = scope->num_kwonly_args; \ + size_t D = scope->num_def_pos_args; \ + \ + /* Adjust S to shrink range, to compress better */ \ + S -= 1; \ + \ + /* Encode prelude */ \ + /* xSSSSEAA */ \ + uint8_t z = (S & 0xf) << 3 | (E & 1) << 2 | (A & 3); \ + S >>= 4; \ + E >>= 1; \ + A >>= 2; \ + while (S | E | F | A | K | D) { \ + out_byte(out_env, 0x80 | z); \ + /* xFSSKAED */ \ + z = (F & 1) << 6 | (S & 3) << 4 | (K & 1) << 3 \ + | (A & 1) << 2 | (E & 1) << 1 | (D & 1); \ + S >>= 2; \ + E >>= 1; \ + F >>= 1; \ + A >>= 1; \ + K >>= 1; \ + D >>= 1; \ + } \ + out_byte(out_env, z); \ +} while (0) + +#define MP_BC_PRELUDE_SIG_DECODE_INTO(ip, S, E, F, A, K, D) \ +do { \ + uint8_t z = *(ip)++; \ + /* xSSSSEAA */ \ + S = (z >> 3) & 0xf; \ + E = (z >> 2) & 0x1; \ + F = 0; \ + A = z & 0x3; \ + K = 0; \ + D = 0; \ + for (unsigned n = 0; z & 0x80; ++n) { \ + z = *(ip)++; \ + /* xFSSKAED */ \ + S |= (z & 0x30) << (2 * n); \ + E |= (z & 0x02) << n; \ + F |= ((z & 0x40) >> 6) << n; \ + A |= (z & 0x4) << n; \ + K |= ((z & 0x08) >> 3) << n; \ + D |= (z & 0x1) << n; \ + } \ + S += 1; \ +} while (0) + +#define MP_BC_PRELUDE_SIG_DECODE(ip) \ + size_t n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args; \ + MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args) + +#define MP_BC_PRELUDE_SIZE_ENCODE(I, C, out_byte, out_env) \ +do { \ + /* Encode bit-wise as: xIIIIIIC */ \ + uint8_t z = 0; \ + do { \ + z = (I & 0x3f) << 1 | (C & 1); \ + C >>= 1; \ + I >>= 6; \ + if (C | I) { \ + z |= 0x80; \ + } \ + out_byte(out_env, z); \ + } while (C | I); \ +} while (0) + +#define MP_BC_PRELUDE_SIZE_DECODE_INTO(ip, I, C) \ +do { \ + uint8_t z; \ + C = 0; \ + I = 0; \ + for (unsigned n = 0;; ++n) { \ + z = *(ip)++; \ + /* xIIIIIIC */ \ + C |= (z & 1) << n; \ + I |= ((z & 0x7e) >> 1) << (6 * n); \ + if (!(z & 0x80)) { \ + break; \ + } \ + } \ +} while (0) + +#define MP_BC_PRELUDE_SIZE_DECODE(ip) \ + size_t n_info, n_cell; \ + MP_BC_PRELUDE_SIZE_DECODE_INTO(ip, n_info, n_cell) + +// Sentinel value for mp_code_state_t.exc_sp_idx +#define MP_CODE_STATE_EXC_SP_IDX_SENTINEL ((uint16_t)-1) + +// To convert mp_code_state_t.exc_sp_idx to/from a pointer to mp_exc_stack_t +#define MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp) ((exc_sp) + 1 - (exc_stack)) +#define MP_CODE_STATE_EXC_SP_IDX_TO_PTR(exc_stack, exc_sp_idx) ((exc_stack) + (exc_sp_idx) - 1) + +typedef struct _mp_bytecode_prelude_t { + uint n_state; + uint n_exc_stack; + uint scope_flags; + uint n_pos_args; + uint n_kwonly_args; + uint n_def_pos_args; + qstr qstr_block_name; + qstr qstr_source_file; + const byte *line_info; + const byte *opcodes; +} mp_bytecode_prelude_t; + // Exception stack entry typedef struct _mp_exc_stack_t { const byte *handler; - // bit 0 is saved currently_in_except_block value + // bit 0 is currently unused // bit 1 is whether the opcode was SETUP_WITH or SETUP_FINALLY mp_obj_t *val_sp; - // Saved exception, valid if currently_in_except_block bit is 1 + // Saved exception mp_obj_base_t *prev_exc; } mp_exc_stack_t; @@ -78,12 +203,16 @@ typedef struct _mp_code_state_t { mp_obj_fun_bc_t *fun_bc; const byte *ip; mp_obj_t *sp; - // bit 0 is saved currently_in_except_block value - mp_exc_stack_t *exc_sp; + uint16_t n_state; + uint16_t exc_sp_idx; mp_obj_dict_t *old_globals; #if MICROPY_STACKLESS struct _mp_code_state_t *prev; #endif + #if MICROPY_PY_SYS_SETTRACE + struct _mp_code_state_t *prev_state; + struct _mp_obj_frame_t *frame; + #endif // Variable-length mp_obj_t state[0]; // Variable-length, never accessed by name, only as (void*)(state + n_state) @@ -110,13 +239,35 @@ const byte *mp_bytecode_print_str(const byte *ip); #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE -#define MP_OPCODE_BYTE (0) -#define MP_OPCODE_QSTR (1) -#define MP_OPCODE_VAR_UINT (2) -#define MP_OPCODE_OFFSET (3) - uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint); #endif +static inline size_t mp_bytecode_get_source_line(const byte *line_info, size_t bc_offset) { + size_t source_line = 1; + size_t c; + while ((c = *line_info)) { + size_t b, l; + if ((c & 0x80) == 0) { + // 0b0LLBBBBB encoding + b = c & 0x1f; + l = c >> 5; + line_info += 1; + } else { + // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) + b = c & 0xf; + l = ((c << 4) & 0x700) | line_info[1]; + line_info += 2; + } + if (bc_offset >= b) { + bc_offset -= b; + source_line += l; + } else { + // found source line corresponding to bytecode offset + break; + } + } + return source_line; +} + #endif // MICROPY_INCLUDED_PY_BC_H diff --git a/micropython/py/bc0.h b/micropython/py/bc0.h index 175ee26..7cf061f 100644 --- a/micropython/py/bc0.h +++ b/micropython/py/bc0.h @@ -26,93 +26,125 @@ #ifndef MICROPY_INCLUDED_PY_BC0_H #define MICROPY_INCLUDED_PY_BC0_H -// MicroPython byte-codes. -// The comment at the end of the line (if it exists) tells the arguments to the byte-code. - -#define MP_BC_LOAD_CONST_FALSE (0x10) -#define MP_BC_LOAD_CONST_NONE (0x11) -#define MP_BC_LOAD_CONST_TRUE (0x12) -#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // signed var-int -#define MP_BC_LOAD_CONST_STRING (0x16) // qstr -#define MP_BC_LOAD_CONST_OBJ (0x17) // ptr -#define MP_BC_LOAD_NULL (0x18) - -#define MP_BC_LOAD_FAST_N (0x19) // uint -#define MP_BC_LOAD_DEREF (0x1a) // uint -#define MP_BC_LOAD_NAME (0x1b) // qstr -#define MP_BC_LOAD_GLOBAL (0x1c) // qstr -#define MP_BC_LOAD_ATTR (0x1d) // qstr -#define MP_BC_LOAD_METHOD (0x1e) // qstr -#define MP_BC_LOAD_SUPER_METHOD (0x1f) // qstr -#define MP_BC_LOAD_BUILD_CLASS (0x20) -#define MP_BC_LOAD_SUBSCR (0x21) - -#define MP_BC_STORE_FAST_N (0x22) // uint -#define MP_BC_STORE_DEREF (0x23) // uint -#define MP_BC_STORE_NAME (0x24) // qstr -#define MP_BC_STORE_GLOBAL (0x25) // qstr -#define MP_BC_STORE_ATTR (0x26) // qstr -#define MP_BC_STORE_SUBSCR (0x27) - -#define MP_BC_DELETE_FAST (0x28) // uint -#define MP_BC_DELETE_DEREF (0x29) // uint -#define MP_BC_DELETE_NAME (0x2a) // qstr -#define MP_BC_DELETE_GLOBAL (0x2b) // qstr - -#define MP_BC_DUP_TOP (0x30) -#define MP_BC_DUP_TOP_TWO (0x31) -#define MP_BC_POP_TOP (0x32) -#define MP_BC_ROT_TWO (0x33) -#define MP_BC_ROT_THREE (0x34) - -#define MP_BC_JUMP (0x35) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_POP_JUMP_IF_TRUE (0x36) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_POP_JUMP_IF_FALSE (0x37) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_JUMP_IF_TRUE_OR_POP (0x38) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_JUMP_IF_FALSE_OR_POP (0x39) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_SETUP_WITH (0x3d) // rel byte code offset, 16-bit unsigned -#define MP_BC_WITH_CLEANUP (0x3e) -#define MP_BC_SETUP_EXCEPT (0x3f) // rel byte code offset, 16-bit unsigned -#define MP_BC_SETUP_FINALLY (0x40) // rel byte code offset, 16-bit unsigned -#define MP_BC_END_FINALLY (0x41) -#define MP_BC_GET_ITER (0x42) -#define MP_BC_FOR_ITER (0x43) // rel byte code offset, 16-bit unsigned -#define MP_BC_POP_EXCEPT_JUMP (0x44) // rel byte code offset, 16-bit unsigned -#define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte -#define MP_BC_GET_ITER_STACK (0x47) - -#define MP_BC_BUILD_TUPLE (0x50) // uint -#define MP_BC_BUILD_LIST (0x51) // uint -#define MP_BC_BUILD_MAP (0x53) // uint -#define MP_BC_STORE_MAP (0x54) -#define MP_BC_BUILD_SET (0x56) // uint -#define MP_BC_BUILD_SLICE (0x58) // uint -#define MP_BC_STORE_COMP (0x57) // uint -#define MP_BC_UNPACK_SEQUENCE (0x59) // uint -#define MP_BC_UNPACK_EX (0x5a) // uint - -#define MP_BC_RETURN_VALUE (0x5b) -#define MP_BC_RAISE_VARARGS (0x5c) // byte -#define MP_BC_YIELD_VALUE (0x5d) -#define MP_BC_YIELD_FROM (0x5e) - -#define MP_BC_MAKE_FUNCTION (0x60) // uint -#define MP_BC_MAKE_FUNCTION_DEFARGS (0x61) // uint -#define MP_BC_MAKE_CLOSURE (0x62) // uint -#define MP_BC_MAKE_CLOSURE_DEFARGS (0x63) // uint -#define MP_BC_CALL_FUNCTION (0x64) // uint -#define MP_BC_CALL_FUNCTION_VAR_KW (0x65) // uint -#define MP_BC_CALL_METHOD (0x66) // uint -#define MP_BC_CALL_METHOD_VAR_KW (0x67) // uint - -#define MP_BC_IMPORT_NAME (0x68) // qstr -#define MP_BC_IMPORT_FROM (0x69) // qstr -#define MP_BC_IMPORT_STAR (0x6a) - -#define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // + N(64) -#define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16) -#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16) -#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(> (2 * ((op) >> 4))) & 3) + +// Load, Store, Delete, Import, Make, Build, Unpack, Call, Jump, Exception, For, sTack, Return, Yield, Op +#define MP_BC_BASE_RESERVED (0x00) // ---------------- +#define MP_BC_BASE_QSTR_O (0x10) // LLLLLLSSSDDII--- +#define MP_BC_BASE_VINT_E (0x20) // MMLLLLSSDDBBBBBB +#define MP_BC_BASE_VINT_O (0x30) // UUMMCCCC-------- +#define MP_BC_BASE_JUMP_E (0x40) // J-JJJJJEEEEF---- +#define MP_BC_BASE_BYTE_O (0x50) // LLLLSSDTTTTTEEFF +#define MP_BC_BASE_BYTE_E (0x60) // --BREEEYYI------ +#define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // LLLLLLLLLLLLLLLL + // (0x80) // LLLLLLLLLLLLLLLL + // (0x90) // LLLLLLLLLLLLLLLL + // (0xa0) // LLLLLLLLLLLLLLLL +#define MP_BC_LOAD_FAST_MULTI (0xb0) // LLLLLLLLLLLLLLLL +#define MP_BC_STORE_FAST_MULTI (0xc0) // SSSSSSSSSSSSSSSS +#define MP_BC_UNARY_OP_MULTI (0xd0) // OOOOOOO +#define MP_BC_BINARY_OP_MULTI (0xd7) // OOOOOOOOO + // (0xe0) // OOOOOOOOOOOOOOOO + // (0xf0) // OOOOOOOOOO------ + +#define MP_BC_LOAD_CONST_SMALL_INT_MULTI_NUM (64) +#define MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS (16) +#define MP_BC_LOAD_FAST_MULTI_NUM (16) +#define MP_BC_STORE_FAST_MULTI_NUM (16) +#define MP_BC_UNARY_OP_MULTI_NUM (MP_UNARY_OP_NUM_BYTECODE) +#define MP_BC_BINARY_OP_MULTI_NUM (MP_BINARY_OP_NUM_BYTECODE) + +#define MP_BC_LOAD_CONST_FALSE (MP_BC_BASE_BYTE_O + 0x00) +#define MP_BC_LOAD_CONST_NONE (MP_BC_BASE_BYTE_O + 0x01) +#define MP_BC_LOAD_CONST_TRUE (MP_BC_BASE_BYTE_O + 0x02) +#define MP_BC_LOAD_CONST_SMALL_INT (MP_BC_BASE_VINT_E + 0x02) // signed var-int +#define MP_BC_LOAD_CONST_STRING (MP_BC_BASE_QSTR_O + 0x00) // qstr +#define MP_BC_LOAD_CONST_OBJ (MP_BC_BASE_VINT_E + 0x03) // ptr +#define MP_BC_LOAD_NULL (MP_BC_BASE_BYTE_O + 0x03) + +#define MP_BC_LOAD_FAST_N (MP_BC_BASE_VINT_E + 0x04) // uint +#define MP_BC_LOAD_DEREF (MP_BC_BASE_VINT_E + 0x05) // uint +#define MP_BC_LOAD_NAME (MP_BC_BASE_QSTR_O + 0x01) // qstr +#define MP_BC_LOAD_GLOBAL (MP_BC_BASE_QSTR_O + 0x02) // qstr +#define MP_BC_LOAD_ATTR (MP_BC_BASE_QSTR_O + 0x03) // qstr +#define MP_BC_LOAD_METHOD (MP_BC_BASE_QSTR_O + 0x04) // qstr +#define MP_BC_LOAD_SUPER_METHOD (MP_BC_BASE_QSTR_O + 0x05) // qstr +#define MP_BC_LOAD_BUILD_CLASS (MP_BC_BASE_BYTE_O + 0x04) +#define MP_BC_LOAD_SUBSCR (MP_BC_BASE_BYTE_O + 0x05) + +#define MP_BC_STORE_FAST_N (MP_BC_BASE_VINT_E + 0x06) // uint +#define MP_BC_STORE_DEREF (MP_BC_BASE_VINT_E + 0x07) // uint +#define MP_BC_STORE_NAME (MP_BC_BASE_QSTR_O + 0x06) // qstr +#define MP_BC_STORE_GLOBAL (MP_BC_BASE_QSTR_O + 0x07) // qstr +#define MP_BC_STORE_ATTR (MP_BC_BASE_QSTR_O + 0x08) // qstr +#define MP_BC_STORE_SUBSCR (MP_BC_BASE_BYTE_O + 0x06) + +#define MP_BC_DELETE_FAST (MP_BC_BASE_VINT_E + 0x08) // uint +#define MP_BC_DELETE_DEREF (MP_BC_BASE_VINT_E + 0x09) // uint +#define MP_BC_DELETE_NAME (MP_BC_BASE_QSTR_O + 0x09) // qstr +#define MP_BC_DELETE_GLOBAL (MP_BC_BASE_QSTR_O + 0x0a) // qstr + +#define MP_BC_DUP_TOP (MP_BC_BASE_BYTE_O + 0x07) +#define MP_BC_DUP_TOP_TWO (MP_BC_BASE_BYTE_O + 0x08) +#define MP_BC_POP_TOP (MP_BC_BASE_BYTE_O + 0x09) +#define MP_BC_ROT_TWO (MP_BC_BASE_BYTE_O + 0x0a) +#define MP_BC_ROT_THREE (MP_BC_BASE_BYTE_O + 0x0b) + +#define MP_BC_JUMP (MP_BC_BASE_JUMP_E + 0x02) // rel byte code offset, 16-bit signed, in excess +#define MP_BC_POP_JUMP_IF_TRUE (MP_BC_BASE_JUMP_E + 0x03) // rel byte code offset, 16-bit signed, in excess +#define MP_BC_POP_JUMP_IF_FALSE (MP_BC_BASE_JUMP_E + 0x04) // rel byte code offset, 16-bit signed, in excess +#define MP_BC_JUMP_IF_TRUE_OR_POP (MP_BC_BASE_JUMP_E + 0x05) // rel byte code offset, 16-bit signed, in excess +#define MP_BC_JUMP_IF_FALSE_OR_POP (MP_BC_BASE_JUMP_E + 0x06) // rel byte code offset, 16-bit signed, in excess +#define MP_BC_UNWIND_JUMP (MP_BC_BASE_JUMP_E + 0x00) // rel byte code offset, 16-bit signed, in excess; then a byte +#define MP_BC_SETUP_WITH (MP_BC_BASE_JUMP_E + 0x07) // rel byte code offset, 16-bit unsigned +#define MP_BC_SETUP_EXCEPT (MP_BC_BASE_JUMP_E + 0x08) // rel byte code offset, 16-bit unsigned +#define MP_BC_SETUP_FINALLY (MP_BC_BASE_JUMP_E + 0x09) // rel byte code offset, 16-bit unsigned +#define MP_BC_POP_EXCEPT_JUMP (MP_BC_BASE_JUMP_E + 0x0a) // rel byte code offset, 16-bit unsigned +#define MP_BC_FOR_ITER (MP_BC_BASE_JUMP_E + 0x0b) // rel byte code offset, 16-bit unsigned +#define MP_BC_WITH_CLEANUP (MP_BC_BASE_BYTE_O + 0x0c) +#define MP_BC_END_FINALLY (MP_BC_BASE_BYTE_O + 0x0d) +#define MP_BC_GET_ITER (MP_BC_BASE_BYTE_O + 0x0e) +#define MP_BC_GET_ITER_STACK (MP_BC_BASE_BYTE_O + 0x0f) + +#define MP_BC_BUILD_TUPLE (MP_BC_BASE_VINT_E + 0x0a) // uint +#define MP_BC_BUILD_LIST (MP_BC_BASE_VINT_E + 0x0b) // uint +#define MP_BC_BUILD_MAP (MP_BC_BASE_VINT_E + 0x0c) // uint +#define MP_BC_STORE_MAP (MP_BC_BASE_BYTE_E + 0x02) +#define MP_BC_BUILD_SET (MP_BC_BASE_VINT_E + 0x0d) // uint +#define MP_BC_BUILD_SLICE (MP_BC_BASE_VINT_E + 0x0e) // uint +#define MP_BC_STORE_COMP (MP_BC_BASE_VINT_E + 0x0f) // uint +#define MP_BC_UNPACK_SEQUENCE (MP_BC_BASE_VINT_O + 0x00) // uint +#define MP_BC_UNPACK_EX (MP_BC_BASE_VINT_O + 0x01) // uint + +#define MP_BC_RETURN_VALUE (MP_BC_BASE_BYTE_E + 0x03) +#define MP_BC_RAISE_LAST (MP_BC_BASE_BYTE_E + 0x04) +#define MP_BC_RAISE_OBJ (MP_BC_BASE_BYTE_E + 0x05) +#define MP_BC_RAISE_FROM (MP_BC_BASE_BYTE_E + 0x06) +#define MP_BC_YIELD_VALUE (MP_BC_BASE_BYTE_E + 0x07) +#define MP_BC_YIELD_FROM (MP_BC_BASE_BYTE_E + 0x08) + +#define MP_BC_MAKE_FUNCTION (MP_BC_BASE_VINT_O + 0x02) // uint +#define MP_BC_MAKE_FUNCTION_DEFARGS (MP_BC_BASE_VINT_O + 0x03) // uint +#define MP_BC_MAKE_CLOSURE (MP_BC_BASE_VINT_E + 0x00) // uint; extra byte +#define MP_BC_MAKE_CLOSURE_DEFARGS (MP_BC_BASE_VINT_E + 0x01) // uint; extra byte +#define MP_BC_CALL_FUNCTION (MP_BC_BASE_VINT_O + 0x04) // uint +#define MP_BC_CALL_FUNCTION_VAR_KW (MP_BC_BASE_VINT_O + 0x05) // uint +#define MP_BC_CALL_METHOD (MP_BC_BASE_VINT_O + 0x06) // uint +#define MP_BC_CALL_METHOD_VAR_KW (MP_BC_BASE_VINT_O + 0x07) // uint + +#define MP_BC_IMPORT_NAME (MP_BC_BASE_QSTR_O + 0x0b) // qstr +#define MP_BC_IMPORT_FROM (MP_BC_BASE_QSTR_O + 0x0c) // qstr +#define MP_BC_IMPORT_STAR (MP_BC_BASE_BYTE_E + 0x09) #endif // MICROPY_INCLUDED_PY_BC0_H diff --git a/micropython/py/binary.c b/micropython/py/binary.c index a142776..83f28db 100644 --- a/micropython/py/binary.c +++ b/micropython/py/binary.c @@ -42,7 +42,7 @@ #define alignof(type) offsetof(struct { char c; type t; }, t) #endif -size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) { +size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) { size_t size = 0; int align = 1; switch (struct_type) { @@ -113,7 +113,7 @@ size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) { return size; } -mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) { +mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) { mp_int_t val = 0; switch (typecode) { case 'b': @@ -162,7 +162,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) { // The long long type is guaranteed to hold at least 64 bits, and size is at // most 8 (for q and Q), so we will always be able to parse the given data // and fit it into a long long. -long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src) { +long long mp_binary_get_int(size_t size, bool is_signed, bool big_endian, const byte *src) { int delta; if (!big_endian) { delta = -1; @@ -185,14 +185,14 @@ long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, con } #define is_signed(typecode) (typecode > 'Z') -mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { +mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr) { byte *p = *ptr; - mp_uint_t align; + size_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { - // Make pointer aligned - p = (byte*)MP_ALIGN(p, (size_t)align); + // Align p relative to p_base + p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align); #if MP_ENDIANNESS_LITTLE struct_type = '<'; #else @@ -231,7 +231,7 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { } } -void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val) { +void mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val) { if (MP_ENDIANNESS_LITTLE && !big_endian) { memcpy(dest, &val, val_sz); } else if (MP_ENDIANNESS_BIG && big_endian) { @@ -250,14 +250,14 @@ void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t } } -void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) { +void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr) { byte *p = *ptr; - mp_uint_t align; + size_t align; size_t size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { - // Make pointer aligned - p = (byte*)MP_ALIGN(p, (size_t)align); + // Align p relative to p_base + p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align); if (MP_ENDIANNESS_LITTLE) { struct_type = '<'; } else { @@ -315,7 +315,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte ** mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val); } -void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in) { +void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in) { switch (typecode) { #if MICROPY_PY_BUILTINS_FLOAT case 'f': @@ -342,7 +342,7 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v } } -void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val) { +void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val) { switch (typecode) { case 'b': ((signed char*)p)[index] = val; diff --git a/micropython/py/binary.h b/micropython/py/binary.h index 7118204..5c645bc 100644 --- a/micropython/py/binary.h +++ b/micropython/py/binary.h @@ -34,13 +34,13 @@ // type-specification errors due to end-of-string. #define BYTEARRAY_TYPECODE 1 -size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign); -mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index); -void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in); -void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val); -mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr); -void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr); -long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src); -void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val); +size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign); +mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index); +void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in); +void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val); +mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr); +void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr); +long long mp_binary_get_int(size_t size, bool is_signed, bool big_endian, const byte *src); +void mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val); #endif // MICROPY_INCLUDED_PY_BINARY_H diff --git a/micropython/py/builtin.h b/micropython/py/builtin.h index 5de8236..b99819e 100644 --- a/micropython/py/builtin.h +++ b/micropython/py/builtin.h @@ -90,7 +90,7 @@ MP_DECLARE_CONST_FUN_OBJ_2(mp_op_delitem_obj); extern mp_obj_module_t mp_module___main__; // LoBo: 'mp_module___main__' is not constant extern const mp_obj_module_t mp_module_builtins; -extern const mp_obj_module_t mp_module_array; +extern const mp_obj_module_t mp_module_uarray; extern const mp_obj_module_t mp_module_collections; extern const mp_obj_module_t mp_module_io; extern const mp_obj_module_t mp_module_math; @@ -123,6 +123,7 @@ extern const mp_obj_module_t mp_module_uwebsocket; extern const mp_obj_module_t mp_module_webrepl; extern const mp_obj_module_t mp_module_framebuf; extern const mp_obj_module_t mp_module_btree; +extern const mp_obj_module_t mp_module_ubluetooth; extern const char MICROPY_PY_BUILTINS_HELP_TEXT[]; diff --git a/micropython/py/builtinhelp.c b/micropython/py/builtinhelp.c index a7fede0..8f162d8 100644 --- a/micropython/py/builtinhelp.c +++ b/micropython/py/builtinhelp.c @@ -80,10 +80,6 @@ STATIC void mp_help_print_modules(void) { mp_help_add_from_map(list, &mp_builtin_module_map); - #if MICROPY_MODULE_WEAK_LINKS - mp_help_add_from_map(list, &mp_builtin_module_weak_links_map); - #endif - #if MICROPY_MODULE_FROZEN_STR extern const char mp_frozen_str_names[]; mp_help_add_from_names(list, mp_frozen_str_names); diff --git a/micropython/py/builtinimport.c b/micropython/py/builtinimport.c index 1a333b5..9d91b20 100644 --- a/micropython/py/builtinimport.c +++ b/micropython/py/builtinimport.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 Damien P. George * Copyright (c) 2014 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -145,11 +145,11 @@ STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { #endif #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_MODULE_FROZEN_MPY -STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) { +STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, const char* source_name) { + (void)source_name; + #if MICROPY_PY___FILE__ - // TODO - //qstr source_name = lex->source_name; - //mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); + mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(qstr_from_str(source_name))); #endif // execute the module in its context @@ -206,7 +206,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // its data) in the list of frozen files, execute it. #if MICROPY_MODULE_FROZEN_MPY if (frozen_type == MP_FROZEN_MPY) { - do_execute_raw_code(module_obj, modref); + do_execute_raw_code(module_obj, modref, file_str); return; } #endif @@ -216,7 +216,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { #if MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD if (file_str[file->len - 3] == 'm') { mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str); - do_execute_raw_code(module_obj, raw_code); + do_execute_raw_code(module_obj, raw_code, file_str); return; } #endif @@ -334,6 +334,10 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { mod_len = new_mod_l; } + if (mod_len == 0) { + mp_raise_ValueError(NULL); + } + // check if module already exists qstr module_name_qstr = mp_obj_str_get_qstr(module_name); mp_obj_t module_obj = mp_module_get(module_name_qstr); @@ -381,21 +385,18 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path)); if (stat == MP_IMPORT_STAT_NO_EXIST) { + module_obj = MP_OBJ_NULL; #if MICROPY_MODULE_WEAK_LINKS // check if there is a weak link to this module if (i == mod_len) { - mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(mod_name), MP_MAP_LOOKUP); - if (el == NULL) { - goto no_exist; + module_obj = mp_module_search_umodule(mod_str); + if (module_obj != MP_OBJ_NULL) { + // found weak linked module + mp_module_call_init(mod_name, module_obj); } - // found weak linked module - module_obj = el->value; - mp_module_call_init(mod_name, module_obj); - } else { - no_exist: - #else - { + } #endif + if (module_obj == MP_OBJ_NULL) { // couldn't find the file, so fail if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_msg(&mp_type_ImportError, "module not found"); @@ -492,11 +493,11 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { #if MICROPY_MODULE_WEAK_LINKS // Check if there is a weak link to this module - mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(module_name_qstr), MP_MAP_LOOKUP); - if (el != NULL) { + module_obj = mp_module_search_umodule(qstr_str(module_name_qstr)); + if (module_obj != MP_OBJ_NULL) { // Found weak-linked module - mp_module_call_init(module_name_qstr, el->value); - return el->value; + mp_module_call_init(module_name_qstr, module_obj); + return module_obj; } #endif diff --git a/micropython/py/compile.c b/micropython/py/compile.c index 84be1b4..3f72d73 100644 --- a/micropython/py/compile.c +++ b/micropython/py/compile.c @@ -96,6 +96,7 @@ STATIC const emit_method_table_t *emit_native_table[] = { &emit_native_thumb_method_table, &emit_native_thumb_method_table, &emit_native_xtensa_method_table, + &emit_native_xtensawin_method_table, }; #elif MICROPY_EMIT_NATIVE @@ -110,6 +111,8 @@ STATIC const emit_method_table_t *emit_native_table[] = { #define NATIVE_EMITTER(f) emit_native_arm_##f #elif MICROPY_EMIT_XTENSA #define NATIVE_EMITTER(f) emit_native_xtensa_##f +#elif MICROPY_EMIT_XTENSAWIN +#define NATIVE_EMITTER(f) emit_native_xtensawin_##f #else #error "unknown native emitter" #endif @@ -132,6 +135,7 @@ STATIC const emit_inline_asm_method_table_t *emit_asm_table[] = { &emit_inline_thumb_method_table, &emit_inline_thumb_method_table, &emit_inline_xtensa_method_table, + NULL, }; #elif MICROPY_EMIT_INLINE_ASM @@ -1034,16 +1038,13 @@ STATIC void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void compile_break_cont_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { uint16_t label; - const char *error_msg; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_break_stmt) { label = comp->break_label; - error_msg = "'break' outside loop"; } else { label = comp->continue_label; - error_msg = "'continue' outside loop"; } if (label == INVALID_LABEL) { - compile_syntax_error(comp, (mp_parse_node_t)pns, error_msg); + compile_syntax_error(comp, (mp_parse_node_t)pns, "'break'/'continue' outside loop"); } assert(comp->cur_except_level >= comp->break_continue_except_level); EMIT_ARG(unwind_jump, label, comp->cur_except_level - comp->break_continue_except_level); @@ -1206,6 +1207,13 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { } while (0); if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) { + #if MICROPY_CPYTHON_COMPAT + if (comp->scope_cur->kind != SCOPE_MODULE) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "import * not at module level"); + return; + } + #endif + EMIT_ARG(load_const_small_int, import_level); // build the "fromlist" tuple @@ -1215,7 +1223,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { // do the import qstr dummy_q; do_import_name(comp, pn_import_source, &dummy_q); - EMIT_ARG(import, MP_QSTR_NULL, MP_EMIT_IMPORT_STAR); + EMIT_ARG(import, MP_QSTRnull, MP_EMIT_IMPORT_STAR); } else { EMIT_ARG(load_const_small_int, import_level); @@ -1618,6 +1626,9 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ qstr qstr_exception_local = 0; uint end_finally_label = comp_next_label(comp); + #if MICROPY_PY_SYS_SETTRACE + EMIT_ARG(set_source_line, pns_except->source_line); + #endif if (MP_PARSE_NODE_IS_NULL(pns_except->nodes[0])) { // this is a catch all exception handler @@ -2003,21 +2014,8 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { c_assign(comp, pns->nodes[0], ASSIGN_AUG_LOAD); // lhs load for aug assign compile_node(comp, pns1->nodes[1]); // rhs assert(MP_PARSE_NODE_IS_TOKEN(pns1->nodes[0])); - mp_binary_op_t op; - switch (MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])) { - case MP_TOKEN_DEL_PIPE_EQUAL: op = MP_BINARY_OP_INPLACE_OR; break; - case MP_TOKEN_DEL_CARET_EQUAL: op = MP_BINARY_OP_INPLACE_XOR; break; - case MP_TOKEN_DEL_AMPERSAND_EQUAL: op = MP_BINARY_OP_INPLACE_AND; break; - case MP_TOKEN_DEL_DBL_LESS_EQUAL: op = MP_BINARY_OP_INPLACE_LSHIFT; break; - case MP_TOKEN_DEL_DBL_MORE_EQUAL: op = MP_BINARY_OP_INPLACE_RSHIFT; break; - case MP_TOKEN_DEL_PLUS_EQUAL: op = MP_BINARY_OP_INPLACE_ADD; break; - case MP_TOKEN_DEL_MINUS_EQUAL: op = MP_BINARY_OP_INPLACE_SUBTRACT; break; - case MP_TOKEN_DEL_STAR_EQUAL: op = MP_BINARY_OP_INPLACE_MULTIPLY; break; - case MP_TOKEN_DEL_DBL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_FLOOR_DIVIDE; break; - case MP_TOKEN_DEL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_TRUE_DIVIDE; break; - case MP_TOKEN_DEL_PERCENT_EQUAL: op = MP_BINARY_OP_INPLACE_MODULO; break; - case MP_TOKEN_DEL_DBL_STAR_EQUAL: default: op = MP_BINARY_OP_INPLACE_POWER; break; - } + mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]); + mp_binary_op_t op = MP_BINARY_OP_INPLACE_OR + (tok - MP_TOKEN_DEL_PIPE_EQUAL); EMIT_ARG(binary_op, op); c_assign(comp, pns->nodes[0], ASSIGN_AUG_STORE); // lhs store for aug assign } else if (kind == PN_expr_stmt_assign_list) { @@ -2151,15 +2149,12 @@ STATIC void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) { EMIT(rot_three); } if (MP_PARSE_NODE_IS_TOKEN(pns->nodes[i])) { + mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]); mp_binary_op_t op; - switch (MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])) { - case MP_TOKEN_OP_LESS: op = MP_BINARY_OP_LESS; break; - case MP_TOKEN_OP_MORE: op = MP_BINARY_OP_MORE; break; - case MP_TOKEN_OP_DBL_EQUAL: op = MP_BINARY_OP_EQUAL; break; - case MP_TOKEN_OP_LESS_EQUAL: op = MP_BINARY_OP_LESS_EQUAL; break; - case MP_TOKEN_OP_MORE_EQUAL: op = MP_BINARY_OP_MORE_EQUAL; break; - case MP_TOKEN_OP_NOT_EQUAL: op = MP_BINARY_OP_NOT_EQUAL; break; - case MP_TOKEN_KW_IN: default: op = MP_BINARY_OP_IN; break; + if (tok == MP_TOKEN_KW_IN) { + op = MP_BINARY_OP_IN; + } else { + op = MP_BINARY_OP_LESS + (tok - MP_TOKEN_OP_LESS); } EMIT_ARG(binary_op, op); } else { @@ -2213,36 +2208,21 @@ STATIC void compile_term(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[0]); for (int i = 1; i + 1 < num_nodes; i += 2) { compile_node(comp, pns->nodes[i + 1]); - mp_binary_op_t op; mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]); - switch (tok) { - case MP_TOKEN_OP_PLUS: op = MP_BINARY_OP_ADD; break; - case MP_TOKEN_OP_MINUS: op = MP_BINARY_OP_SUBTRACT; break; - case MP_TOKEN_OP_STAR: op = MP_BINARY_OP_MULTIPLY; break; - case MP_TOKEN_OP_DBL_SLASH: op = MP_BINARY_OP_FLOOR_DIVIDE; break; - case MP_TOKEN_OP_SLASH: op = MP_BINARY_OP_TRUE_DIVIDE; break; - case MP_TOKEN_OP_PERCENT: op = MP_BINARY_OP_MODULO; break; - case MP_TOKEN_OP_DBL_LESS: op = MP_BINARY_OP_LSHIFT; break; - default: - assert(tok == MP_TOKEN_OP_DBL_MORE); - op = MP_BINARY_OP_RSHIFT; - break; - } + mp_binary_op_t op = MP_BINARY_OP_LSHIFT + (tok - MP_TOKEN_OP_DBL_LESS); EMIT_ARG(binary_op, op); } } STATIC void compile_factor_2(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[1]); - mp_unary_op_t op; mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); - switch (tok) { - case MP_TOKEN_OP_PLUS: op = MP_UNARY_OP_POSITIVE; break; - case MP_TOKEN_OP_MINUS: op = MP_UNARY_OP_NEGATIVE; break; - default: - assert(tok == MP_TOKEN_OP_TILDE); - op = MP_UNARY_OP_INVERT; - break; + mp_unary_op_t op; + if (tok == MP_TOKEN_OP_TILDE) { + op = MP_UNARY_OP_INVERT; + } else { + assert(tok == MP_TOKEN_OP_PLUS || tok == MP_TOKEN_OP_MINUS); + op = MP_UNARY_OP_POSITIVE + (tok - MP_TOKEN_OP_PLUS); } EMIT_ARG(unary_op, op); } @@ -2861,7 +2841,7 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn return; } - qstr param_name = MP_QSTR_NULL; + qstr param_name = MP_QSTRnull; uint param_flag = ID_FLAG_IS_PARAM; mp_parse_node_struct_t *pns = NULL; if (MP_PARSE_NODE_IS_ID(pn)) { @@ -2920,7 +2900,7 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn } } - if (param_name != MP_QSTR_NULL) { + if (param_name != MP_QSTRnull) { id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, param_name, ID_INFO_KIND_UNDECIDED); if (id_info->kind != ID_INFO_KIND_UNDECIDED) { compile_syntax_error(comp, pn, "argument name reused"); @@ -3088,6 +3068,9 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 3); + // Set the source line number for the start of the lambda + EMIT_ARG(set_source_line, pns->source_line); + // work out number of parameters, keywords and default parameters, and add them to the id_info array // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc) if (comp->pass == MP_PASS_SCOPE) { @@ -3122,6 +3105,9 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { scope->num_pos_args = 1; } + // Set the source line number for the start of the comprehension + EMIT_ARG(set_source_line, pns->source_line); + if (scope->kind == SCOPE_LIST_COMP) { EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST); } else if (scope->kind == SCOPE_DICT_COMP) { @@ -3161,6 +3147,9 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { scope_find_or_add_id(scope, MP_QSTR___class__, ID_INFO_KIND_LOCAL); } + #if MICROPY_PY_SYS_SETTRACE + EMIT_ARG(set_source_line, pns->source_line); + #endif compile_load_id(comp, MP_QSTR___name__); compile_store_id(comp, MP_QSTR___module__); EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); // 0 is class name @@ -3444,7 +3433,7 @@ STATIC void scope_compute_things(scope_t *scope) { #if !MICROPY_PERSISTENT_CODE_SAVE STATIC #endif -mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl) { +mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) { // put compiler state on the stack, it's relatively small compiler_t comp_state = {0}; compiler_t *comp = &comp_state; @@ -3455,6 +3444,11 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f comp->continue_label = INVALID_LABEL; // create the module scope + #if MICROPY_EMIT_NATIVE + const uint emit_opt = MP_STATE_VM(default_emit_opt); + #else + const uint emit_opt = MP_EMIT_OPT_NONE; + #endif scope_t *module_scope = scope_new_and_link(comp, SCOPE_MODULE, parse_tree->root, emit_opt); // create standard emitter; it's used at least for MP_PASS_SCOPE @@ -3609,8 +3603,8 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f } } -mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl) { - mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, emit_opt, is_repl); +mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) { + mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, is_repl); // return function that executes the outer module return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); } diff --git a/micropython/py/compile.h b/micropython/py/compile.h index 99a17a8..1ad1f5e 100644 --- a/micropython/py/compile.h +++ b/micropython/py/compile.h @@ -32,11 +32,11 @@ // the compiler will raise an exception if an error occurred // the compiler will clear the parse tree before it returns -mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl); +mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl); #if MICROPY_PERSISTENT_CODE_SAVE // this has the same semantics as mp_compile -mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl); +mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl); #endif // this is implemented in runtime.c diff --git a/micropython/py/dynruntime.h b/micropython/py/dynruntime.h new file mode 100644 index 0000000..7092a5d --- /dev/null +++ b/micropython/py/dynruntime.h @@ -0,0 +1,218 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_DYNRUNTIME_H +#define MICROPY_INCLUDED_PY_DYNRUNTIME_H + +// This header file contains definitions to dynamically implement the static +// MicroPython runtime API defined in py/obj.h and py/runtime.h. + +#include "py/nativeglue.h" +#include "py/objstr.h" + +#undef MP_ROM_QSTR +#undef MP_OBJ_QSTR_VALUE +#undef MP_OBJ_NEW_QSTR +#undef mp_const_none +#undef mp_const_false +#undef mp_const_true +#undef mp_const_empty_tuple +#undef nlr_raise + +/******************************************************************************/ +// Memory allocation + +#define m_malloc(n) (m_malloc_dyn((n))) +#define m_free(ptr) (m_free_dyn((ptr))) +#define m_realloc(ptr, new_num_bytes) (m_realloc_dyn((ptr), (new_num_bytes))) + +static inline void *m_malloc_dyn(size_t n) { + // TODO won't raise on OOM + return mp_fun_table.realloc_(NULL, n, false); +} + +static inline void m_free_dyn(void *ptr) { + mp_fun_table.realloc_(ptr, 0, false); +} + +static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) { + // TODO won't raise on OOM + return mp_fun_table.realloc_(ptr, new_num_bytes, true); +} + +/******************************************************************************/ +// Printing + +#define mp_plat_print (*mp_fun_table.plat_print) +#define mp_printf(p, ...) (mp_fun_table.printf_((p), __VA_ARGS__)) +#define mp_vprintf(p, fmt, args) (mp_fun_table.vprintf_((p), (fmt), (args))) + +/******************************************************************************/ +// Types and objects + +#define MP_OBJ_NEW_QSTR(x) MP_OBJ_NEW_QSTR_ ## x + +#define mp_type_type (*mp_fun_table.type_type) +#define mp_type_str (*mp_fun_table.type_str) +#define mp_type_list (*mp_fun_table.type_list) +#define mp_type_EOFError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_EOFError))) +#define mp_type_IndexError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_IndexError))) +#define mp_type_KeyError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_KeyError))) +#define mp_type_NotImplementedError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_NotImplementedError))) +#define mp_type_RuntimeError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_RuntimeError))) +#define mp_type_TypeError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_TypeError))) +#define mp_type_ValueError (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_ValueError))) + +#define mp_stream_read_obj (*mp_fun_table.stream_read_obj) +#define mp_stream_readinto_obj (*mp_fun_table.stream_readinto_obj) +#define mp_stream_unbuffered_readline_obj (*mp_fun_table.stream_unbuffered_readline_obj) +#define mp_stream_write_obj (*mp_fun_table.stream_write_obj) + +#define mp_const_none ((mp_obj_t)mp_fun_table.const_none) +#define mp_const_false ((mp_obj_t)mp_fun_table.const_false) +#define mp_const_true ((mp_obj_t)mp_fun_table.const_true) +#define mp_const_empty_tuple (mp_fun_table.new_tuple(0, NULL)) + +#define mp_obj_new_bool(b) ((b) ? (mp_obj_t)mp_fun_table.const_true : (mp_obj_t)mp_fun_table.const_false) +#define mp_obj_new_int(i) (mp_fun_table.native_to_obj(i, MP_NATIVE_TYPE_INT)) +#define mp_obj_new_int_from_uint(i) (mp_fun_table.native_to_obj(i, MP_NATIVE_TYPE_UINT)) +#define mp_obj_new_str(data, len) (mp_fun_table.obj_new_str((data), (len))) +#define mp_obj_new_str_of_type(t, d, l) (mp_obj_new_str_of_type_dyn((t), (d), (l))) +#define mp_obj_new_bytes(data, len) (mp_fun_table.obj_new_bytes((data), (len))) +#define mp_obj_new_bytearray_by_ref(n, i) (mp_fun_table.obj_new_bytearray_by_ref((n), (i))) +#define mp_obj_new_tuple(n, items) (mp_fun_table.new_tuple((n), (items))) +#define mp_obj_new_list(n, items) (mp_fun_table.new_list((n), (items))) + +#define mp_obj_get_type(o) (mp_fun_table.obj_get_type((o))) +#define mp_obj_get_int(o) (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_INT)) +#define mp_obj_get_int_truncated(o) (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_UINT)) +#define mp_obj_str_get_str(s) ((void*)mp_fun_table.native_from_obj(s, MP_NATIVE_TYPE_PTR)) +#define mp_obj_str_get_data(o, len) (mp_obj_str_get_data_dyn((o), (len))) +#define mp_get_buffer_raise(o, bufinfo, fl) (mp_fun_table.get_buffer_raise((o), (bufinfo), (fl))) +#define mp_get_stream_raise(s, flags) (mp_fun_table.get_stream_raise((s), (flags))) + +#define mp_obj_len(o) (mp_obj_len_dyn(o)) +#define mp_obj_subscr(base, index, val) (mp_fun_table.obj_subscr((base), (index), (val))) +#define mp_obj_list_append(list, item) (mp_fun_table.list_append((list), (item))) + +static inline mp_obj_t mp_obj_new_str_of_type_dyn(const mp_obj_type_t *type, const byte* data, size_t len) { + if (type == &mp_type_str) { + return mp_obj_new_str((const char*)data, len); + } else { + return mp_obj_new_bytes(data, len); + } +} + +static inline void *mp_obj_str_get_data_dyn(mp_obj_t o, size_t *l) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(o, &bufinfo, MP_BUFFER_READ); + *l = bufinfo.len; + return bufinfo.buf; +} + +static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) { + // If bytes implemented MP_UNARY_OP_LEN could use: mp_unary_op(MP_UNARY_OP_LEN, o) + return mp_fun_table.call_function_n_kw(mp_fun_table.load_name(MP_QSTR_len), 1, &o); +} + +/******************************************************************************/ +// General runtime functions + +#define mp_load_name(qst) (mp_fun_table.load_name(qst)) +#define mp_load_global(qst) (mp_fun_table.load_global(qst)) +#define mp_store_global(qst, obj) (mp_fun_table.store_global((qst), (obj))) +#define mp_unary_op(op, obj) (mp_fun_table.unary_op((op), (obj))) +#define mp_binary_op(op, lhs, rhs) (mp_fun_table.binary_op((op), (lhs), (rhs))) + +#define mp_make_function_from_raw_code(rc, def_args, def_kw_args) \ + (mp_fun_table.make_function_from_raw_code((rc), (def_args), (def_kw_args))) + +#define mp_call_function_n_kw(fun, n_args, n_kw, args) \ + (mp_fun_table.call_function_n_kw((fun), (n_args) | ((n_kw) << 8), args)) + +#define mp_arg_check_num(n_args, n_kw, n_args_min, n_args_max, takes_kw) \ + (mp_fun_table.arg_check_num_sig((n_args), (n_kw), MP_OBJ_FUN_MAKE_SIG((n_args_min), (n_args_max), (takes_kw)))) + +#define MP_DYNRUNTIME_INIT_ENTRY \ + mp_obj_t old_globals = mp_fun_table.swap_globals(self->globals); \ + mp_raw_code_t rc; \ + rc.kind = MP_CODE_NATIVE_VIPER; \ + rc.scope_flags = 0; \ + rc.const_table = (void*)self->const_table; \ + (void)rc; + +#define MP_DYNRUNTIME_INIT_EXIT \ + mp_fun_table.swap_globals(old_globals); \ + return mp_const_none; + +#define MP_DYNRUNTIME_MAKE_FUNCTION(f) \ + (mp_make_function_from_raw_code((rc.fun_data = (f), &rc), MP_OBJ_NULL, MP_OBJ_NULL)) + +/******************************************************************************/ +// Exceptions + +#define mp_obj_new_exception(o) ((mp_obj_t)(o)) // Assumes returned object will be raised, will create instance then +#define mp_obj_new_exception_arg1(e_type, arg) (mp_obj_new_exception_arg1_dyn((e_type), (arg))) + +#define nlr_raise(o) (mp_raise_dyn(o)) +#define mp_raise_msg(type, msg) (mp_fun_table.raise_msg((type), (msg))) +#define mp_raise_OSError(er) (mp_raise_OSError_dyn(er)) +#define mp_raise_NotImplementedError(msg) (mp_raise_msg(&mp_type_NotImplementedError, (msg))) +#define mp_raise_TypeError(msg) (mp_raise_msg(&mp_type_TypeError, (msg))) +#define mp_raise_ValueError(msg) (mp_raise_msg(&mp_type_ValueError, (msg))) + +static inline mp_obj_t mp_obj_new_exception_arg1_dyn(const mp_obj_type_t *exc_type, mp_obj_t arg) { + mp_obj_t args[1] = { arg }; + return mp_call_function_n_kw(MP_OBJ_FROM_PTR(exc_type), 1, 0, &args[0]); +} + +static NORETURN inline void mp_raise_dyn(mp_obj_t o) { + mp_fun_table.raise(o); + for (;;) { + } +} + +static inline void mp_raise_OSError_dyn(int er) { + mp_obj_t args[1] = { MP_OBJ_NEW_SMALL_INT(er) }; + nlr_raise(mp_call_function_n_kw(mp_load_global(MP_QSTR_OSError), 1, 0, &args[0])); +} + +/******************************************************************************/ +// Floating point + +#define mp_obj_new_float_from_f(f) (mp_fun_table.obj_new_float_from_f((f))) +#define mp_obj_new_float_from_d(d) (mp_fun_table.obj_new_float_from_d((d))) +#define mp_obj_get_float_to_f(o) (mp_fun_table.obj_get_float_to_f((o))) +#define mp_obj_get_float_to_d(o) (mp_fun_table.obj_get_float_to_d((o))) + +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define mp_obj_new_float(f) (mp_obj_new_float_from_f((f))) +#define mp_obj_get_float(o) (mp_obj_get_float_to_f((o))) +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define mp_obj_new_float(f) (mp_obj_new_float_from_d((f))) +#define mp_obj_get_float(o) (mp_obj_get_float_to_d((o))) +#endif + +#endif // MICROPY_INCLUDED_PY_DYNRUNTIME_H diff --git a/micropython/py/dynruntime.mk b/micropython/py/dynruntime.mk new file mode 100644 index 0000000..8b65745 --- /dev/null +++ b/micropython/py/dynruntime.mk @@ -0,0 +1,144 @@ +# Makefile fragment for generating native .mpy files from C source +# MPY_DIR must be set to the top of the MicroPython source tree + +BUILD ?= build + +ECHO = @echo +RM = /bin/rm +MKDIR = /bin/mkdir +PYTHON = python3 +MPY_CROSS = $(MPY_DIR)/mpy-cross/mpy-cross +MPY_TOOL = $(PYTHON) $(MPY_DIR)/tools/mpy-tool.py +MPY_LD = $(PYTHON) $(MPY_DIR)/tools/mpy_ld.py + +Q = @ +ifeq ("$(origin V)", "command line") +ifeq ($(V),1) +Q = +MPY_LD += '-vvv' +endif +endif + +ARCH_UPPER = $(shell echo $(ARCH) | tr '[:lower:]' '[:upper:]') +CONFIG_H = $(BUILD)/$(MOD).config.h + +CFLAGS += -I. -I$(MPY_DIR) +CFLAGS += -std=c99 +CFLAGS += -Os +CFLAGS += -Wall -Werror -DNDEBUG +CFLAGS += -DNO_QSTR +CFLAGS += -DMP_CONFIGFILE='<$(CONFIG_H)>' +CFLAGS += -fpic -fno-common +CFLAGS += -U _FORTIFY_SOURCE # prevent use of __*_chk libc functions +#CFLAGS += -fdata-sections -ffunction-sections + +MPY_CROSS_FLAGS += -march=$(ARCH) + +SRC_O += $(addprefix $(BUILD)/, $(patsubst %.c,%.o,$(filter %.c,$(SRC)))) +SRC_MPY += $(addprefix $(BUILD)/, $(patsubst %.py,%.mpy,$(filter %.py,$(SRC)))) + +################################################################################ +# Architecture configuration + +ifeq ($(ARCH),x86) + +# x86 +CROSS = +CFLAGS += -m32 -fno-stack-protector +MPY_CROSS_FLAGS += -mcache-lookup-bc +MICROPY_FLOAT_IMPL ?= double + +else ifeq ($(ARCH),x64) + +# x64 +CROSS = +CFLAGS += -fno-stack-protector +MPY_CROSS_FLAGS += -mcache-lookup-bc +MICROPY_FLOAT_IMPL ?= double + +else ifeq ($(ARCH),armv7m) + +# thumb +CROSS = arm-none-eabi- +CFLAGS += -mthumb -mcpu=cortex-m3 +MICROPY_FLOAT_IMPL ?= none + +else ifeq ($(ARCH),armv7emsp) + +# thumb +CROSS = arm-none-eabi- +CFLAGS += -mthumb -mcpu=cortex-m4 +CFLAGS += -mfpu=fpv4-sp-d16 -mfloat-abi=hard +MICROPY_FLOAT_IMPL ?= float + +else ifeq ($(ARCH),armv7emdp) + +# thumb +CROSS = arm-none-eabi- +CFLAGS += -mthumb -mcpu=cortex-m7 +CFLAGS += -mfpu=fpv5-d16 -mfloat-abi=hard +MICROPY_FLOAT_IMPL ?= double + +else ifeq ($(ARCH),xtensa) + +# xtensa +CROSS = xtensa-lx106-elf- +CFLAGS += -mforce-l32 +MICROPY_FLOAT_IMPL ?= none + +else ifeq ($(ARCH),xtensawin) + +# xtensawin +CROSS = xtensa-esp32-elf- +CFLAGS += +MICROPY_FLOAT_IMPL ?= float + +else +$(error architecture '$(ARCH)' not supported) +endif + +MICROPY_FLOAT_IMPL_UPPER = $(shell echo $(MICROPY_FLOAT_IMPL) | tr '[:lower:]' '[:upper:]') +CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_$(MICROPY_FLOAT_IMPL_UPPER) + +CFLAGS += $(CFLAGS_EXTRA) + +################################################################################ +# Build rules + +.PHONY: all clean + +all: $(MOD).mpy + +clean: + $(RM) -rf $(BUILD) $(CLEAN_EXTRA) + +# Create build destination directories first +BUILD_DIRS = $(sort $(dir $(CONFIG_H) $(SRC_O) $(SRC_MPY))) +$(CONFIG_H) $(SRC_O) $(SRC_MPY): | $(BUILD_DIRS) +$(BUILD_DIRS): + $(Q)$(MKDIR) -p $@ + +# Preprocess all source files to generate $(CONFIG_H) +$(CONFIG_H): $(SRC) + $(ECHO) "GEN $@" + $(Q)$(MPY_LD) --arch $(ARCH) --preprocess -o $@ $^ + +# Build .o from .c source files +$(BUILD)/%.o: %.c $(CONFIG_H) Makefile + $(ECHO) "CC $<" + $(Q)$(CROSS)gcc $(CFLAGS) -o $@ -c $< + +# Build .mpy from .py source files +$(BUILD)/%.mpy: %.py + $(ECHO) "MPY $<" + $(Q)$(MPY_CROSS) $(MPY_CROSS_FLAGS) -o $@ $< + +# Build native .mpy from object files +$(BUILD)/$(MOD).native.mpy: $(SRC_O) + $(ECHO) "LINK $<" + $(Q)$(MPY_LD) --arch $(ARCH) --qstrs $(CONFIG_H) -o $@ $^ + +# Build final .mpy from all intermediate .mpy files +$(MOD).mpy: $(BUILD)/$(MOD).native.mpy $(SRC_MPY) + $(ECHO) "GEN $@" + $(Q)$(MPY_TOOL) --merge -o $@ $^ diff --git a/micropython/py/emit.h b/micropython/py/emit.h index 70f7bf1..26d027a 100644 --- a/micropython/py/emit.h +++ b/micropython/py/emit.h @@ -76,15 +76,15 @@ typedef enum { // Kind for emit->setup_block() #define MP_EMIT_SETUP_BLOCK_WITH (0) -#define MP_EMIT_SETUP_BLOCK_EXCEPT (2) -#define MP_EMIT_SETUP_BLOCK_FINALLY (3) +#define MP_EMIT_SETUP_BLOCK_EXCEPT (1) +#define MP_EMIT_SETUP_BLOCK_FINALLY (2) // Kind for emit->build() #define MP_EMIT_BUILD_TUPLE (0) #define MP_EMIT_BUILD_LIST (1) -#define MP_EMIT_BUILD_MAP (3) -#define MP_EMIT_BUILD_SET (6) -#define MP_EMIT_BUILD_SLICE (8) +#define MP_EMIT_BUILD_MAP (2) +#define MP_EMIT_BUILD_SET (3) +#define MP_EMIT_BUILD_SLICE (4) // Kind for emit->yield() #define MP_EMIT_YIELD_VALUE (0) @@ -174,6 +174,7 @@ extern const emit_method_table_t emit_native_x86_method_table; extern const emit_method_table_t emit_native_thumb_method_table; extern const emit_method_table_t emit_native_arm_method_table; extern const emit_method_table_t emit_native_xtensa_method_table; +extern const emit_method_table_t emit_native_xtensawin_method_table; extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops; extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops; @@ -185,6 +186,7 @@ emit_t *emit_native_x86_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t ma emit_t *emit_native_thumb_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); emit_t *emit_native_arm_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); emit_t *emit_native_xtensa_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); +emit_t *emit_native_xtensawin_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); void emit_bc_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels); @@ -194,6 +196,7 @@ void emit_native_x86_free(emit_t *emit); void emit_native_thumb_free(emit_t *emit); void emit_native_arm_free(emit_t *emit); void emit_native_xtensa_free(emit_t *emit); +void emit_native_xtensawin_free(emit_t *emit); void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope); void mp_emit_bc_end_pass(emit_t *emit); diff --git a/micropython/py/emitbc.c b/micropython/py/emitbc.c index 35eb6df..34f6362 100644 --- a/micropython/py/emitbc.c +++ b/micropython/py/emitbc.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -64,6 +64,9 @@ struct _emit_t { size_t bytecode_size; byte *code_base; // stores both byte code and code info + size_t n_info; + size_t n_cell; + #if MICROPY_PERSISTENT_CODE uint16_t ct_cur_obj; uint16_t ct_num_obj; @@ -123,10 +126,6 @@ STATIC void emit_write_code_info_byte(emit_t* emit, byte val) { *emit_get_cur_to_write_code_info(emit, 1) = val; } -STATIC void emit_write_code_info_uint(emit_t* emit, mp_uint_t val) { - emit_write_uint(emit, emit_get_cur_to_write_code_info, val); -} - STATIC void emit_write_code_info_qstr(emit_t *emit, qstr qst) { #if MICROPY_PERSISTENT_CODE assert((qst >> 16) == 0); @@ -182,20 +181,20 @@ STATIC byte *emit_get_cur_to_write_bytecode(emit_t *emit, int num_bytes_to_write } } -STATIC void emit_write_bytecode_byte(emit_t *emit, byte b1) { +STATIC void emit_write_bytecode_raw_byte(emit_t *emit, byte b1) { byte *c = emit_get_cur_to_write_bytecode(emit, 1); c[0] = b1; } -STATIC void emit_write_bytecode_byte_byte(emit_t* emit, byte b1, byte b2) { - byte *c = emit_get_cur_to_write_bytecode(emit, 2); +STATIC void emit_write_bytecode_byte(emit_t *emit, int stack_adj, byte b1) { + mp_emit_bc_adjust_stack_size(emit, stack_adj); + byte *c = emit_get_cur_to_write_bytecode(emit, 1); c[0] = b1; - c[1] = b2; } // Similar to emit_write_bytecode_uint(), just some extra handling to encode sign -STATIC void emit_write_bytecode_byte_int(emit_t *emit, byte b1, mp_int_t num) { - emit_write_bytecode_byte(emit, b1); +STATIC void emit_write_bytecode_byte_int(emit_t *emit, int stack_adj, byte b1, mp_int_t num) { + emit_write_bytecode_byte(emit, stack_adj, b1); // We store each 7 bits in a separate byte, and that's how many bytes needed byte buf[BYTES_FOR_INT]; @@ -220,40 +219,41 @@ STATIC void emit_write_bytecode_byte_int(emit_t *emit, byte b1, mp_int_t num) { *c = *p; } -STATIC void emit_write_bytecode_byte_uint(emit_t *emit, byte b, mp_uint_t val) { - emit_write_bytecode_byte(emit, b); +STATIC void emit_write_bytecode_byte_uint(emit_t *emit, int stack_adj, byte b, mp_uint_t val) { + emit_write_bytecode_byte(emit, stack_adj, b); emit_write_uint(emit, emit_get_cur_to_write_bytecode, val); } #if MICROPY_PERSISTENT_CODE -STATIC void emit_write_bytecode_byte_const(emit_t *emit, byte b, mp_uint_t n, mp_uint_t c) { +STATIC void emit_write_bytecode_byte_const(emit_t *emit, int stack_adj, byte b, mp_uint_t n, mp_uint_t c) { if (emit->pass == MP_PASS_EMIT) { emit->const_table[n] = c; } - emit_write_bytecode_byte_uint(emit, b, n); + emit_write_bytecode_byte_uint(emit, stack_adj, b, n); } #endif -STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, byte b, qstr qst) { +STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, int stack_adj, byte b, qstr qst) { #if MICROPY_PERSISTENT_CODE assert((qst >> 16) == 0); + mp_emit_bc_adjust_stack_size(emit, stack_adj); byte *c = emit_get_cur_to_write_bytecode(emit, 3); c[0] = b; c[1] = qst; c[2] = qst >> 8; #else - emit_write_bytecode_byte_uint(emit, b, qst); + emit_write_bytecode_byte_uint(emit, stack_adj, b, qst); #endif } -STATIC void emit_write_bytecode_byte_obj(emit_t *emit, byte b, mp_obj_t obj) { +STATIC void emit_write_bytecode_byte_obj(emit_t *emit, int stack_adj, byte b, mp_obj_t obj) { #if MICROPY_PERSISTENT_CODE - emit_write_bytecode_byte_const(emit, b, + emit_write_bytecode_byte_const(emit, stack_adj, b, emit->scope->num_pos_args + emit->scope->num_kwonly_args + emit->ct_cur_obj++, (mp_uint_t)obj); #else // aligns the pointer so it is friendly to GC - emit_write_bytecode_byte(emit, b); + emit_write_bytecode_byte(emit, stack_adj, b); emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(mp_obj_t)); mp_obj_t *c = (mp_obj_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_obj_t)); // Verify thar c is already uint-aligned @@ -262,24 +262,28 @@ STATIC void emit_write_bytecode_byte_obj(emit_t *emit, byte b, mp_obj_t obj) { #endif } -STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, byte b, mp_raw_code_t *rc) { +STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, int stack_adj, byte b, mp_raw_code_t *rc) { #if MICROPY_PERSISTENT_CODE - emit_write_bytecode_byte_const(emit, b, + emit_write_bytecode_byte_const(emit, stack_adj, b, emit->scope->num_pos_args + emit->scope->num_kwonly_args + emit->ct_num_obj + emit->ct_cur_raw_code++, (mp_uint_t)(uintptr_t)rc); #else // aligns the pointer so it is friendly to GC - emit_write_bytecode_byte(emit, b); + emit_write_bytecode_byte(emit, stack_adj, b); emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(void*)); void **c = (void**)emit_get_cur_to_write_bytecode(emit, sizeof(void*)); // Verify thar c is already uint-aligned assert(c == MP_ALIGN(c, sizeof(void*))); *c = rc; #endif + #if MICROPY_PY_SYS_SETTRACE + rc->line_of_definition = emit->last_source_line; + #endif } // unsigned labels are relative to ip following this instruction, stored as 16 bits -STATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, byte b1, mp_uint_t label) { +STATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, int stack_adj, byte b1, mp_uint_t label) { + mp_emit_bc_adjust_stack_size(emit, stack_adj); mp_uint_t bytecode_offset; if (emit->pass < MP_PASS_EMIT) { bytecode_offset = 0; @@ -293,7 +297,8 @@ STATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, byte b1, mp_ui } // signed labels are relative to ip following this instruction, stored as 16 bits, in excess -STATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, byte b1, mp_uint_t label) { +STATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, int stack_adj, byte b1, mp_uint_t label) { + mp_emit_bc_adjust_stack_size(emit, stack_adj); int bytecode_offset; if (emit->pass < MP_PASS_EMIT) { bytecode_offset = 0; @@ -322,7 +327,7 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { emit->bytecode_offset = 0; emit->code_info_offset = 0; - // Write local state size and exception stack size. + // Write local state size, exception stack size, scope flags and number of arguments { mp_uint_t n_state = scope->num_locals + scope->stack_size; if (n_state == 0) { @@ -335,40 +340,22 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { // An extra slot in the stack is needed to detect VM stack overflow n_state += 1; #endif - emit_write_code_info_uint(emit, n_state); - emit_write_code_info_uint(emit, scope->exc_stack_size); - } - // Write scope flags and number of arguments. - // TODO check that num args all fit in a byte - emit_write_code_info_byte(emit, emit->scope->scope_flags); - emit_write_code_info_byte(emit, emit->scope->num_pos_args); - emit_write_code_info_byte(emit, emit->scope->num_kwonly_args); - emit_write_code_info_byte(emit, emit->scope->num_def_pos_args); + size_t n_exc_stack = scope->exc_stack_size; + MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, scope, emit_write_code_info_byte, emit); + } - // Write size of the rest of the code info. We don't know how big this - // variable uint will be on the MP_PASS_CODE_SIZE pass so we reserve 2 bytes - // for it and hope that is enough! TODO assert this or something. - if (pass == MP_PASS_EMIT) { - emit_write_code_info_uint(emit, emit->code_info_size - emit->code_info_offset); - } else { - emit_get_cur_to_write_code_info(emit, 2); + // Write number of cells and size of the source code info + if (pass >= MP_PASS_CODE_SIZE) { + MP_BC_PRELUDE_SIZE_ENCODE(emit->n_info, emit->n_cell, emit_write_code_info_byte, emit); } + emit->n_info = emit->code_info_offset; + // Write the name and source file of this function. emit_write_code_info_qstr(emit, scope->simple_name); emit_write_code_info_qstr(emit, scope->source_file); - // bytecode prelude: initialise closed over variables - for (int i = 0; i < scope->id_info_len; i++) { - id_info_t *id = &scope->id_info[i]; - if (id->kind == ID_INFO_KIND_CELL) { - assert(id->local_num < 255); - emit_write_bytecode_byte(emit, id->local_num); // write the local which should be converted to a cell - } - } - emit_write_bytecode_byte(emit, 255); // end of list sentinel - #if MICROPY_PERSISTENT_CODE emit->ct_cur_obj = 0; emit->ct_cur_raw_code = 0; @@ -414,6 +401,20 @@ void mp_emit_bc_end_pass(emit_t *emit) { emit_write_code_info_byte(emit, 0); // end of line number info + // Calculate size of source code info section + emit->n_info = emit->code_info_offset - emit->n_info; + + // Emit closure section of prelude + emit->n_cell = 0; + for (size_t i = 0; i < emit->scope->id_info_len; ++i) { + id_info_t *id = &emit->scope->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL) { + assert(id->local_num <= 255); + emit_write_code_info_byte(emit, id->local_num); // write the local which should be converted to a cell + ++emit->n_cell; + } + } + #if MICROPY_PERSISTENT_CODE assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->ct_num_obj == emit->ct_cur_obj)); emit->ct_num_obj = emit->ct_cur_obj; @@ -468,10 +469,6 @@ void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) { emit->last_emit_was_return_value = false; } -static inline void emit_bc_pre(emit_t *emit, mp_int_t stack_size_delta) { - mp_emit_bc_adjust_stack_size(emit, stack_size_delta); -} - void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) { //printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset); #if MICROPY_ENABLE_SOURCE_LINE @@ -493,7 +490,7 @@ void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) { } void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) { - emit_bc_pre(emit, 0); + mp_emit_bc_adjust_stack_size(emit, 0); if (emit->pass == MP_PASS_SCOPE) { return; } @@ -511,64 +508,54 @@ void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) { void mp_emit_bc_import(emit_t *emit, qstr qst, int kind) { MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_NAME == MP_BC_IMPORT_NAME); MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_FROM == MP_BC_IMPORT_FROM); - if (kind == MP_EMIT_IMPORT_FROM) { - emit_bc_pre(emit, 1); - } else { - emit_bc_pre(emit, -1); - } + int stack_adj = kind == MP_EMIT_IMPORT_FROM ? 1 : -1; if (kind == MP_EMIT_IMPORT_STAR) { - emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR); + emit_write_bytecode_byte(emit, stack_adj, MP_BC_IMPORT_STAR); } else { - emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME + kind, qst); + emit_write_bytecode_byte_qstr(emit, stack_adj, MP_BC_IMPORT_NAME + kind, qst); } } void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) { - emit_bc_pre(emit, 1); - switch (tok) { - case MP_TOKEN_KW_FALSE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE); break; - case MP_TOKEN_KW_NONE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_NONE); break; - case MP_TOKEN_KW_TRUE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_TRUE); break; - default: - assert(tok == MP_TOKEN_ELLIPSIS); - emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); - break; + MP_STATIC_ASSERT(MP_BC_LOAD_CONST_FALSE + (MP_TOKEN_KW_NONE - MP_TOKEN_KW_FALSE) == MP_BC_LOAD_CONST_NONE); + MP_STATIC_ASSERT(MP_BC_LOAD_CONST_FALSE + (MP_TOKEN_KW_TRUE - MP_TOKEN_KW_FALSE) == MP_BC_LOAD_CONST_TRUE); + if (tok == MP_TOKEN_ELLIPSIS) { + emit_write_bytecode_byte_obj(emit, 1, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); + } else { + emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_CONST_FALSE + (tok - MP_TOKEN_KW_FALSE)); } } void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) { - emit_bc_pre(emit, 1); - if (-16 <= arg && arg <= 47) { - emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_SMALL_INT_MULTI + 16 + arg); + if (-MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS <= arg + && arg < MP_BC_LOAD_CONST_SMALL_INT_MULTI_NUM - MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS) { + emit_write_bytecode_byte(emit, 1, + MP_BC_LOAD_CONST_SMALL_INT_MULTI + MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS + arg); } else { - emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg); + emit_write_bytecode_byte_int(emit, 1, MP_BC_LOAD_CONST_SMALL_INT, arg); } } void mp_emit_bc_load_const_str(emit_t *emit, qstr qst) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_STRING, qst); + emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_CONST_STRING, qst); } void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, obj); + emit_write_bytecode_byte_obj(emit, 1, MP_BC_LOAD_CONST_OBJ, obj); } void mp_emit_bc_load_null(emit_t *emit) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL); + emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_NULL); } void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_LOAD_FAST_N); MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_LOAD_DEREF); (void)qst; - emit_bc_pre(emit, 1); if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) { - emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num); + emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_FAST_MULTI + local_num); } else { - emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N + kind, local_num); + emit_write_bytecode_byte_uint(emit, 1, MP_BC_LOAD_FAST_N + kind, local_num); } } @@ -576,51 +563,45 @@ void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) { MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_LOAD_NAME); MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL); (void)qst; - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME + kind, qst); + emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_NAME + kind, qst); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { - emit_write_bytecode_byte(emit, 0); + emit_write_bytecode_raw_byte(emit, 0); } } void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) { - emit_bc_pre(emit, 1 - 2 * is_super); - emit_write_bytecode_byte_qstr(emit, is_super ? MP_BC_LOAD_SUPER_METHOD : MP_BC_LOAD_METHOD, qst); + int stack_adj = 1 - 2 * is_super; + emit_write_bytecode_byte_qstr(emit, stack_adj, is_super ? MP_BC_LOAD_SUPER_METHOD : MP_BC_LOAD_METHOD, qst); } void mp_emit_bc_load_build_class(emit_t *emit) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte(emit, MP_BC_LOAD_BUILD_CLASS); + emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_BUILD_CLASS); } void mp_emit_bc_subscr(emit_t *emit, int kind) { if (kind == MP_EMIT_SUBSCR_LOAD) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR); + emit_write_bytecode_byte(emit, -1, MP_BC_LOAD_SUBSCR); } else { if (kind == MP_EMIT_SUBSCR_DELETE) { mp_emit_bc_load_null(emit); mp_emit_bc_rot_three(emit); } - emit_bc_pre(emit, -3); - emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR); + emit_write_bytecode_byte(emit, -3, MP_BC_STORE_SUBSCR); } } void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) { if (kind == MP_EMIT_ATTR_LOAD) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst); + emit_write_bytecode_byte_qstr(emit, 0, MP_BC_LOAD_ATTR, qst); } else { if (kind == MP_EMIT_ATTR_DELETE) { mp_emit_bc_load_null(emit); mp_emit_bc_rot_two(emit); } - emit_bc_pre(emit, -2); - emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst); + emit_write_bytecode_byte_qstr(emit, -2, MP_BC_STORE_ATTR, qst); } if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { - emit_write_bytecode_byte(emit, 0); + emit_write_bytecode_raw_byte(emit, 0); } } @@ -628,98 +609,86 @@ void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kin MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_STORE_FAST_N); MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_STORE_DEREF); (void)qst; - emit_bc_pre(emit, -1); if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) { - emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num); + emit_write_bytecode_byte(emit, -1, MP_BC_STORE_FAST_MULTI + local_num); } else { - emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N + kind, local_num); + emit_write_bytecode_byte_uint(emit, -1, MP_BC_STORE_FAST_N + kind, local_num); } } void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind) { MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_STORE_NAME); MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_STORE_GLOBAL); - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME + kind, qst); + emit_write_bytecode_byte_qstr(emit, -1, MP_BC_STORE_NAME + kind, qst); } void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_DELETE_FAST); MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_DELETE_DEREF); (void)qst; - emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST + kind, local_num); + emit_write_bytecode_byte_uint(emit, 0, MP_BC_DELETE_FAST + kind, local_num); } void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind) { MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_DELETE_NAME); MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_DELETE_GLOBAL); - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME + kind, qst); + emit_write_bytecode_byte_qstr(emit, 0, MP_BC_DELETE_NAME + kind, qst); } void mp_emit_bc_dup_top(emit_t *emit) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte(emit, MP_BC_DUP_TOP); + emit_write_bytecode_byte(emit, 1, MP_BC_DUP_TOP); } void mp_emit_bc_dup_top_two(emit_t *emit) { - emit_bc_pre(emit, 2); - emit_write_bytecode_byte(emit, MP_BC_DUP_TOP_TWO); + emit_write_bytecode_byte(emit, 2, MP_BC_DUP_TOP_TWO); } void mp_emit_bc_pop_top(emit_t *emit) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_POP_TOP); + emit_write_bytecode_byte(emit, -1, MP_BC_POP_TOP); } void mp_emit_bc_rot_two(emit_t *emit) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_ROT_TWO); + emit_write_bytecode_byte(emit, 0, MP_BC_ROT_TWO); } void mp_emit_bc_rot_three(emit_t *emit) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_ROT_THREE); + emit_write_bytecode_byte(emit, 0, MP_BC_ROT_THREE); } void mp_emit_bc_jump(emit_t *emit, mp_uint_t label) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label); + emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_JUMP, label); } void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) { - emit_bc_pre(emit, -1); if (cond) { - emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_TRUE, label); + emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_POP_JUMP_IF_TRUE, label); } else { - emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_FALSE, label); + emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_POP_JUMP_IF_FALSE, label); } } void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) { - emit_bc_pre(emit, -1); if (cond) { - emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_TRUE_OR_POP, label); + emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_JUMP_IF_TRUE_OR_POP, label); } else { - emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label); + emit_write_bytecode_byte_signed_label(emit, -1, MP_BC_JUMP_IF_FALSE_OR_POP, label); } } void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { if (except_depth == 0) { - emit_bc_pre(emit, 0); if (label & MP_EMIT_BREAK_FROM_FOR) { // need to pop the iterator if we are breaking out of a for loop - emit_write_bytecode_byte(emit, MP_BC_POP_TOP); + emit_write_bytecode_raw_byte(emit, MP_BC_POP_TOP); // also pop the iter_buf for (size_t i = 0; i < MP_OBJ_ITER_BUF_NSLOTS - 1; ++i) { - emit_write_bytecode_byte(emit, MP_BC_POP_TOP); + emit_write_bytecode_raw_byte(emit, MP_BC_POP_TOP); } } - emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); + emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); } else { - emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); - emit_write_bytecode_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth); + emit_write_bytecode_byte_signed_label(emit, 0, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); + emit_write_bytecode_raw_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth); } } @@ -727,52 +696,45 @@ void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind) { MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_WITH == MP_BC_SETUP_WITH); MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_EXCEPT == MP_BC_SETUP_EXCEPT); MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_FINALLY == MP_BC_SETUP_FINALLY); - if (kind == MP_EMIT_SETUP_BLOCK_WITH) { // The SETUP_WITH opcode pops ctx_mgr from the top of the stack // and then pushes 3 entries: __exit__, ctx_mgr, as_value. - emit_bc_pre(emit, 2); - } else { - emit_bc_pre(emit, 0); - } - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH + kind, label); + int stack_adj = kind == MP_EMIT_SETUP_BLOCK_WITH ? 2 : 0; + emit_write_bytecode_byte_unsigned_label(emit, stack_adj, MP_BC_SETUP_WITH + kind, label); } void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE); mp_emit_bc_label_assign(emit, label); - emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method - emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP); - emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_block(MP_EMIT_SETUP_BLOCK_WITH) + // The +2 is to ensure we have enough stack space to call the __exit__ method + emit_write_bytecode_byte(emit, 2, MP_BC_WITH_CLEANUP); + // Cancel the +2 above, plus the +2 from mp_emit_bc_setup_block(MP_EMIT_SETUP_BLOCK_WITH) + mp_emit_bc_adjust_stack_size(emit, -4); } void mp_emit_bc_end_finally(emit_t *emit) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_END_FINALLY); + emit_write_bytecode_byte(emit, -1, MP_BC_END_FINALLY); } void mp_emit_bc_get_iter(emit_t *emit, bool use_stack) { - emit_bc_pre(emit, use_stack ? MP_OBJ_ITER_BUF_NSLOTS - 1 : 0); - emit_write_bytecode_byte(emit, use_stack ? MP_BC_GET_ITER_STACK : MP_BC_GET_ITER); + int stack_adj = use_stack ? MP_OBJ_ITER_BUF_NSLOTS - 1 : 0; + emit_write_bytecode_byte(emit, stack_adj, use_stack ? MP_BC_GET_ITER_STACK : MP_BC_GET_ITER); } void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_FOR_ITER, label); + emit_write_bytecode_byte_unsigned_label(emit, 1, MP_BC_FOR_ITER, label); } void mp_emit_bc_for_iter_end(emit_t *emit) { - emit_bc_pre(emit, -MP_OBJ_ITER_BUF_NSLOTS); + mp_emit_bc_adjust_stack_size(emit, -MP_OBJ_ITER_BUF_NSLOTS); } void mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) { (void)within_exc_handler; - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_POP_EXCEPT_JUMP, label); + emit_write_bytecode_byte_unsigned_label(emit, 0, MP_BC_POP_EXCEPT_JUMP, label); } void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + op); + emit_write_bytecode_byte(emit, 0, MP_BC_UNARY_OP_MULTI + op); } void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) { @@ -784,11 +746,9 @@ void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) { invert = true; op = MP_BINARY_OP_IS; } - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_BINARY_OP_MULTI + op); + emit_write_bytecode_byte(emit, -1, MP_BC_BINARY_OP_MULTI + op); if (invert) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NOT); + emit_write_bytecode_byte(emit, 0, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NOT); } } @@ -798,17 +758,12 @@ void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind) { MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_BC_BUILD_MAP); MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_BC_BUILD_SET); MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SLICE == MP_BC_BUILD_SLICE); - if (kind == MP_EMIT_BUILD_MAP) { - emit_bc_pre(emit, 1); - } else { - emit_bc_pre(emit, 1 - n_args); - } - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE + kind, n_args); + int stack_adj = kind == MP_EMIT_BUILD_MAP ? 1 : 1 - n_args; + emit_write_bytecode_byte_uint(emit, stack_adj, MP_BC_BUILD_TUPLE + kind, n_args); } void mp_emit_bc_store_map(emit_t *emit) { - emit_bc_pre(emit, -2); - emit_write_bytecode_byte(emit, MP_BC_STORE_MAP); + emit_write_bytecode_byte(emit, -2, MP_BC_STORE_MAP); } void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_stack_index) { @@ -824,51 +779,46 @@ void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection n = 0; t = 2; } - emit_bc_pre(emit, -1 - n); // the lower 2 bits of the opcode argument indicate the collection type - emit_write_bytecode_byte_uint(emit, MP_BC_STORE_COMP, ((collection_stack_index + n) << 2) | t); + emit_write_bytecode_byte_uint(emit, -1 - n, MP_BC_STORE_COMP, ((collection_stack_index + n) << 2) | t); } void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, -1 + n_args); - emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_SEQUENCE, n_args); + emit_write_bytecode_byte_uint(emit, -1 + n_args, MP_BC_UNPACK_SEQUENCE, n_args); } void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) { - emit_bc_pre(emit, -1 + n_left + n_right + 1); - emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_EX, n_left | (n_right << 8)); + emit_write_bytecode_byte_uint(emit, -1 + n_left + n_right + 1, MP_BC_UNPACK_EX, n_left | (n_right << 8)); } void mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { if (n_pos_defaults == 0 && n_kw_defaults == 0) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_FUNCTION, scope->raw_code); + emit_write_bytecode_byte_raw_code(emit, 1, MP_BC_MAKE_FUNCTION, scope->raw_code); } else { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code); + emit_write_bytecode_byte_raw_code(emit, -1, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code); } } void mp_emit_bc_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { if (n_pos_defaults == 0 && n_kw_defaults == 0) { - emit_bc_pre(emit, -n_closed_over + 1); - emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_CLOSURE, scope->raw_code); - emit_write_bytecode_byte(emit, n_closed_over); + int stack_adj = -n_closed_over + 1; + emit_write_bytecode_byte_raw_code(emit, stack_adj, MP_BC_MAKE_CLOSURE, scope->raw_code); + emit_write_bytecode_raw_byte(emit, n_closed_over); } else { assert(n_closed_over <= 255); - emit_bc_pre(emit, -2 - (mp_int_t)n_closed_over + 1); - emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code); - emit_write_bytecode_byte(emit, n_closed_over); + int stack_adj = -2 - (mp_int_t)n_closed_over + 1; + emit_write_bytecode_byte_raw_code(emit, stack_adj, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code); + emit_write_bytecode_raw_byte(emit, n_closed_over); } } -STATIC void emit_bc_call_function_method_helper(emit_t *emit, mp_int_t stack_adj, mp_uint_t bytecode_base, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { +STATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, mp_uint_t bytecode_base, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { if (star_flags) { - emit_bc_pre(emit, stack_adj - (mp_int_t)n_positional - 2 * (mp_int_t)n_keyword - 2); - emit_write_bytecode_byte_uint(emit, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? + stack_adj -= (int)n_positional + 2 * (int)n_keyword + 2; + emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? } else { - emit_bc_pre(emit, stack_adj - (mp_int_t)n_positional - 2 * (mp_int_t)n_keyword); - emit_write_bytecode_byte_uint(emit, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? + stack_adj -= (int)n_positional + 2 * (int)n_keyword; + emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? } } @@ -881,22 +831,21 @@ void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_ke } void mp_emit_bc_return_value(emit_t *emit) { - emit_bc_pre(emit, -1); + emit_write_bytecode_byte(emit, -1, MP_BC_RETURN_VALUE); emit->last_emit_was_return_value = true; - emit_write_bytecode_byte(emit, MP_BC_RETURN_VALUE); } void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) { + MP_STATIC_ASSERT(MP_BC_RAISE_LAST + 1 == MP_BC_RAISE_OBJ); + MP_STATIC_ASSERT(MP_BC_RAISE_LAST + 2 == MP_BC_RAISE_FROM); assert(n_args <= 2); - emit_bc_pre(emit, -n_args); - emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args); + emit_write_bytecode_byte(emit, -n_args, MP_BC_RAISE_LAST + n_args); } void mp_emit_bc_yield(emit_t *emit, int kind) { MP_STATIC_ASSERT(MP_BC_YIELD_VALUE + 1 == MP_BC_YIELD_FROM); - emit_bc_pre(emit, -kind); + emit_write_bytecode_byte(emit, -kind, MP_BC_YIELD_VALUE + kind); emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; - emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE + kind); } void mp_emit_bc_start_except_handler(emit_t *emit) { diff --git a/micropython/py/emitglue.c b/micropython/py/emitglue.c index c073258..d30a1e6 100644 --- a/micropython/py/emitglue.c +++ b/micropython/py/emitglue.c @@ -34,6 +34,7 @@ #include "py/emitglue.h" #include "py/runtime0.h" #include "py/bc.h" +#include "py/profile.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) @@ -52,6 +53,9 @@ mp_uint_t mp_verbose_flag = 0; mp_raw_code_t *mp_emit_glue_new_raw_code(void) { mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1); rc->kind = MP_CODE_RESERVED; + #if MICROPY_PY_SYS_SETTRACE + rc->line_of_definition = 0; + #endif return rc; } @@ -75,6 +79,11 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, rc->n_raw_code = n_raw_code; #endif + #if MICROPY_PY_SYS_SETTRACE + mp_bytecode_prelude_t *prelude = &rc->prelude; + mp_prof_extract_prelude(code, prelude); + #endif + #ifdef DEBUG_PRINT #if !MICROPY_DEBUG_PRINTERS const size_t len = 0; @@ -88,7 +97,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, #endif } -#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM +#if MICROPY_EMIT_MACHINE_CODE void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, #if MICROPY_PERSISTENT_CODE_SAVE uint16_t prelude_offset, @@ -172,6 +181,12 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) { ((mp_obj_base_t*)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap; } + + #if MICROPY_PY_SYS_SETTRACE + mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t *)MP_OBJ_TO_PTR(fun); + self_fun->rc = rc; + #endif + break; } diff --git a/micropython/py/emitglue.h b/micropython/py/emitglue.h index 058f060..a5411dc 100644 --- a/micropython/py/emitglue.h +++ b/micropython/py/emitglue.h @@ -27,6 +27,7 @@ #define MICROPY_INCLUDED_PY_EMITGLUE_H #include "py/obj.h" +#include "py/bc.h" // These variables and functions glue the code emitters to the runtime. @@ -63,13 +64,21 @@ typedef struct _mp_raw_code_t { size_t fun_data_len; uint16_t n_obj; uint16_t n_raw_code; - #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM + #if MICROPY_PY_SYS_SETTRACE + mp_bytecode_prelude_t prelude; + // line_of_definition is a Python source line where the raw_code was + // created e.g. MP_BC_MAKE_FUNCTION. This is different from lineno info + // stored in prelude, which provides line number for first statement of + // a function. Required to properly implement "call" trace event. + mp_uint_t line_of_definition; + #endif + #if MICROPY_EMIT_MACHINE_CODE uint16_t prelude_offset; uint16_t n_qstr; mp_qstr_link_entry_t *qstr_link; #endif #endif - #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM + #if MICROPY_EMIT_MACHINE_CODE mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc #endif } mp_raw_code_t; diff --git a/micropython/py/emitnative.c b/micropython/py/emitnative.c index f123ecb..07b984b 100644 --- a/micropython/py/emitnative.c +++ b/micropython/py/emitnative.c @@ -47,7 +47,8 @@ #include #include "py/emit.h" -#include "py/bc.h" +#include "py/nativeglue.h" +#include "py/objstr.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) @@ -57,7 +58,7 @@ #endif // wrapper around everything in this file -#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA +#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA || N_XTENSAWIN // C stack layout for native functions: // 0: nlr_buf_t [optional] @@ -80,6 +81,30 @@ // locals (reversed, L0 at end) | // (L0-L2 may be in regs instead) +// Native emitter needs to know the following sizes and offsets of C structs (on the target): +#if MICROPY_DYNAMIC_COMPILER +#define SIZEOF_NLR_BUF (2 + mp_dynamic_compiler.nlr_buf_num_regs + 1) // the +1 is conservative in case MICROPY_ENABLE_PYSTACK enabled +#else +#define SIZEOF_NLR_BUF (sizeof(nlr_buf_t) / sizeof(uintptr_t)) +#endif +#define SIZEOF_CODE_STATE (sizeof(mp_code_state_t) / sizeof(uintptr_t)) +#define OFFSETOF_CODE_STATE_STATE (offsetof(mp_code_state_t, state) / sizeof(uintptr_t)) +#define OFFSETOF_CODE_STATE_FUN_BC (offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t)) +#define OFFSETOF_CODE_STATE_IP (offsetof(mp_code_state_t, ip) / sizeof(uintptr_t)) +#define OFFSETOF_CODE_STATE_SP (offsetof(mp_code_state_t, sp) / sizeof(uintptr_t)) +#define OFFSETOF_OBJ_FUN_BC_GLOBALS (offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t)) +#define OFFSETOF_OBJ_FUN_BC_BYTECODE (offsetof(mp_obj_fun_bc_t, bytecode) / sizeof(uintptr_t)) +#define OFFSETOF_OBJ_FUN_BC_CONST_TABLE (offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)) + +// If not already defined, set parent args to same as child call registers +#ifndef REG_PARENT_RET +#define REG_PARENT_RET REG_RET +#define REG_PARENT_ARG_1 REG_ARG_1 +#define REG_PARENT_ARG_2 REG_ARG_2 +#define REG_PARENT_ARG_3 REG_ARG_3 +#define REG_PARENT_ARG_4 REG_ARG_4 +#endif + // Word index of nlr_buf_t.ret_val #define NLR_BUF_IDX_RET_VAL (1) @@ -101,9 +126,9 @@ #define LOCAL_IDX_EXC_HANDLER_PC(emit) (NLR_BUF_IDX_LOCAL_1) #define LOCAL_IDX_EXC_HANDLER_UNWIND(emit) (NLR_BUF_IDX_LOCAL_2) #define LOCAL_IDX_RET_VAL(emit) (NLR_BUF_IDX_LOCAL_3) -#define LOCAL_IDX_FUN_OBJ(emit) ((emit)->code_state_start + offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t)) -#define LOCAL_IDX_OLD_GLOBALS(emit) ((emit)->code_state_start + offsetof(mp_code_state_t, ip) / sizeof(uintptr_t)) -#define LOCAL_IDX_GEN_PC(emit) ((emit)->code_state_start + offsetof(mp_code_state_t, ip) / sizeof(uintptr_t)) +#define LOCAL_IDX_FUN_OBJ(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_FUN_BC) +#define LOCAL_IDX_OLD_GLOBALS(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_IP) +#define LOCAL_IDX_GEN_PC(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_IP) #define LOCAL_IDX_LOCAL_VAR(emit, local_num) ((emit)->stack_start + (emit)->n_state - 1 - (local_num)) #define REG_GENERATOR_STATE (REG_LOCAL_3) @@ -194,6 +219,7 @@ struct _emit_t { uint16_t code_state_start; uint16_t stack_start; int stack_size; + uint16_t n_cell; uint16_t const_table_cur_obj; uint16_t const_table_num_obj; @@ -309,7 +335,11 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->pass = pass; emit->do_viper_types = scope->emit_options == MP_EMIT_OPT_VIPER; emit->stack_size = 0; + #if N_PRELUDE_AS_BYTES_OBJ + emit->const_table_cur_obj = emit->do_viper_types ? 0 : 1; // reserve first obj for prelude bytes obj + #else emit->const_table_cur_obj = 0; + #endif emit->const_table_cur_raw_code = 0; #if MICROPY_PERSISTENT_CODE_SAVE emit->qstr_link_cur = 0; @@ -364,7 +394,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop // Work out start of code state (mp_code_state_t or reduced version for viper) emit->code_state_start = 0; if (NEED_GLOBAL_EXC_HANDLER(emit)) { - emit->code_state_start = sizeof(nlr_buf_t) / sizeof(uintptr_t); + emit->code_state_start = SIZEOF_NLR_BUF; } if (emit->do_viper_types) { @@ -398,16 +428,16 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs); #if N_X86 - asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1); + asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1); #endif // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table - ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_ARG_1, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE); ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, 0); // Store function object (passed as first arg) to stack if needed if (NEED_FUN_OBJ(emit)) { - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_ARG_1); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1); } // Put n_args in REG_ARG_1, n_kw in REG_ARG_2, args array in REG_LOCAL_3 @@ -416,9 +446,9 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_2); asm_x86_mov_arg_to_r32(emit->as, 3, REG_LOCAL_3); #else - ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_ARG_2); - ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_ARG_3); - ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_4); + ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_PARENT_ARG_2); + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_3); + ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_4); #endif // Check number of args matches this function, and call mp_arg_check_num_sig if not @@ -458,31 +488,36 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { emit->code_state_start = 0; - emit->stack_start = sizeof(mp_code_state_t) / sizeof(mp_uint_t); + emit->stack_start = SIZEOF_CODE_STATE; + #if N_PRELUDE_AS_BYTES_OBJ + // Load index of prelude bytes object in const_table + mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)(emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1)); + #else mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->prelude_offset); + #endif mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->start_offset); - ASM_ENTRY(emit->as, sizeof(nlr_buf_t) / sizeof(uintptr_t)); + ASM_ENTRY(emit->as, SIZEOF_NLR_BUF); // Put address of code_state into REG_GENERATOR_STATE #if N_X86 asm_x86_mov_arg_to_r32(emit->as, 0, REG_GENERATOR_STATE); #else - ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_ARG_1); + ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_PARENT_ARG_1); #endif // Put throw value into LOCAL_IDX_EXC_VAL slot, for yield/yield-from #if N_X86 - asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_2); + asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2); #endif - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_ARG_2); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_PARENT_ARG_2); // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, LOCAL_IDX_FUN_OBJ(emit)); - ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONST_TABLE); ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_TEMP0, emit->scope->num_pos_args + emit->scope->num_kwonly_args); } else { // The locals and stack start after the code_state structure - emit->stack_start = emit->code_state_start + sizeof(mp_code_state_t) / sizeof(mp_uint_t); + emit->stack_start = emit->code_state_start + SIZEOF_CODE_STATE; // Allocate space on C-stack for code_state structure, which includes state ASM_ENTRY(emit->as, emit->stack_start + emit->n_state); @@ -490,26 +525,49 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop // Prepare incoming arguments for call to mp_setup_code_state #if N_X86 - asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1); - asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_2); - asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_3); - asm_x86_mov_arg_to_r32(emit->as, 3, REG_ARG_4); + asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1); + asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2); + asm_x86_mov_arg_to_r32(emit->as, 2, REG_PARENT_ARG_3); + asm_x86_mov_arg_to_r32(emit->as, 3, REG_PARENT_ARG_4); #endif // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table - ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_ARG_1, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE); ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args); // Set code_state.fun_bc - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_ARG_1); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1); // Set code_state.ip (offset from start of this function to prelude info) + #if N_PRELUDE_AS_BYTES_OBJ + // Prelude is a bytes object in const_table; store ip = prelude->data - fun_bc->bytecode + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_LOCAL_3, offsetof(mp_obj_str_t, data) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_PARENT_ARG_1, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_BYTECODE); + ASM_SUB_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1); + emit_native_mov_state_reg(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, REG_LOCAL_3); + #else // TODO this encoding may change size in the final pass, need to make it fixed - emit_native_mov_state_imm_via(emit, emit->code_state_start + offsetof(mp_code_state_t, ip) / sizeof(uintptr_t), emit->prelude_offset, REG_ARG_1); + emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_PARENT_ARG_1); + #endif + + // Set code_state.n_state (only works on little endian targets due to n_state being uint16_t) + emit_native_mov_state_imm_via(emit, emit->code_state_start + offsetof(mp_code_state_t, n_state) / sizeof(uintptr_t), emit->n_state, REG_ARG_1); // Put address of code_state into first arg ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, emit->code_state_start); + // Copy next 3 args if needed + #if REG_ARG_2 != REG_PARENT_ARG_2 + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_2); + #endif + #if REG_ARG_3 != REG_PARENT_ARG_3 + ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_PARENT_ARG_3); + #endif + #if REG_ARG_4 != REG_PARENT_ARG_4 + ASM_MOV_REG_REG(emit->as, REG_ARG_4, REG_PARENT_ARG_4); + #endif + // Call mp_setup_code_state to prepare code_state structure #if N_THUMB asm_thumb_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4); @@ -556,22 +614,28 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop } +static inline void emit_native_write_code_info_byte(emit_t *emit, byte val) { + mp_asm_base_data(&emit->as->base, 1, val); +} + STATIC void emit_native_end_pass(emit_t *emit) { emit_native_global_exc_exit(emit); if (!emit->do_viper_types) { emit->prelude_offset = mp_asm_base_get_code_pos(&emit->as->base); - mp_asm_base_data(&emit->as->base, 1, 0x80 | ((emit->n_state >> 7) & 0x7f)); - mp_asm_base_data(&emit->as->base, 1, emit->n_state & 0x7f); - mp_asm_base_data(&emit->as->base, 1, 0); // n_exc_stack - mp_asm_base_data(&emit->as->base, 1, emit->scope->scope_flags); - mp_asm_base_data(&emit->as->base, 1, emit->scope->num_pos_args); - mp_asm_base_data(&emit->as->base, 1, emit->scope->num_kwonly_args); - mp_asm_base_data(&emit->as->base, 1, emit->scope->num_def_pos_args); - - // write code info + + size_t n_state = emit->n_state; + size_t n_exc_stack = 0; // exc-stack not needed for native code + MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, emit->scope, emit_native_write_code_info_byte, emit); + + #if MICROPY_PERSISTENT_CODE + size_t n_info = 4; + #else + size_t n_info = 1; + #endif + MP_BC_PRELUDE_SIZE_ENCODE(n_info, emit->n_cell, emit_native_write_code_info_byte, emit); + #if MICROPY_PERSISTENT_CODE - mp_asm_base_data(&emit->as->base, 1, 5); mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name); mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name >> 8); mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file); @@ -581,14 +645,25 @@ STATIC void emit_native_end_pass(emit_t *emit) { #endif // bytecode prelude: initialise closed over variables + size_t cell_start = mp_asm_base_get_code_pos(&emit->as->base); for (int i = 0; i < emit->scope->id_info_len; i++) { id_info_t *id = &emit->scope->id_info[i]; if (id->kind == ID_INFO_KIND_CELL) { - assert(id->local_num < 255); + assert(id->local_num <= 255); mp_asm_base_data(&emit->as->base, 1, id->local_num); // write the local which should be converted to a cell } } - mp_asm_base_data(&emit->as->base, 1, 255); // end of list sentinel + emit->n_cell = mp_asm_base_get_code_pos(&emit->as->base) - cell_start; + + #if N_PRELUDE_AS_BYTES_OBJ + // Prelude bytes object is after qstr arg names and mp_fun_table + size_t table_off = emit->scope->num_pos_args + emit->scope->num_kwonly_args + 1; + if (emit->pass == MP_PASS_EMIT) { + void *buf = emit->as->base.code_base + emit->prelude_offset; + size_t n = emit->as->base.code_offset - emit->prelude_offset; + emit->const_table[table_off] = (uintptr_t)mp_obj_new_bytes(buf, n); + } + #endif } ASM_END_PASS(emit->as); @@ -609,8 +684,11 @@ STATIC void emit_native_end_pass(emit_t *emit) { const_table_alloc += nqstr; } emit->const_table = m_new(mp_uint_t, const_table_alloc); + #if !MICROPY_DYNAMIC_COMPILER // Store mp_fun_table pointer just after qstrs - emit->const_table[nqstr] = (mp_uint_t)(uintptr_t)mp_fun_table; + // (but in dynamic-compiler mode eliminate dependency on mp_fun_table) + emit->const_table[nqstr] = (mp_uint_t)(uintptr_t)&mp_fun_table; + #endif #if MICROPY_PERSISTENT_CODE_SAVE size_t qstr_link_alloc = emit->qstr_link_cur; @@ -1033,7 +1111,7 @@ STATIC void emit_load_reg_with_ptr(emit_t *emit, int reg, mp_uint_t ptr, size_t emit->const_table[table_off] = ptr; } emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_FUN_OBJ(emit)); - ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONST_TABLE); ASM_LOAD_REG_REG_OFFSET(emit->as, reg, REG_TEMP0, table_off); } @@ -1090,7 +1168,7 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) { // Set new globals emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_FUN_OBJ(emit)); - ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, OFFSETOF_OBJ_FUN_BC_GLOBALS); emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS); // Save old globals (or NULL if globals didn't change) @@ -1106,6 +1184,10 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { // Wrap everything in an nlr context ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0); emit_call(emit, MP_F_NLR_PUSH); + #if N_NLR_SETJMP + ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 2); + emit_call(emit, MP_F_SETJMP); + #endif ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, true); } else { // Clear the unwind state @@ -1120,6 +1202,10 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_2, LOCAL_IDX_EXC_HANDLER_UNWIND(emit)); ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0); emit_call(emit, MP_F_NLR_PUSH); + #if N_NLR_SETJMP + ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 2); + emit_call(emit, MP_F_SETJMP); + #endif ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_LOCAL_2); ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, global_except_label, true); @@ -1130,6 +1216,12 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { // Global exception handler: check for valid exception handler emit_native_label_assign(emit, global_except_label); + #if N_NLR_SETJMP + // Reload REG_FUN_TABLE, since it may be clobbered by longjmp + emit_native_mov_reg_state(emit, REG_LOCAL_1, LOCAL_IDX_FUN_OBJ(emit)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_1, REG_LOCAL_1, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_1, emit->scope->num_pos_args + emit->scope->num_kwonly_args); + #endif ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_1, LOCAL_IDX_EXC_HANDLER_PC(emit)); ASM_JUMP_IF_REG_NONZERO(emit->as, REG_LOCAL_1, nlr_label, false); } @@ -1143,10 +1235,10 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) { if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { // Store return value in state[0] ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, LOCAL_IDX_EXC_VAL(emit)); - ASM_STORE_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, offsetof(mp_code_state_t, state) / sizeof(uintptr_t)); + ASM_STORE_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, OFFSETOF_CODE_STATE_STATE); // Load return kind - ASM_MOV_REG_IMM(emit->as, REG_RET, MP_VM_RETURN_EXCEPTION); + ASM_MOV_REG_IMM(emit->as, REG_PARENT_RET, MP_VM_RETURN_EXCEPTION); ASM_EXIT(emit->as); } else { @@ -1201,7 +1293,7 @@ STATIC void emit_native_global_exc_exit(emit_t *emit) { } // Load return value - ASM_MOV_REG_LOCAL(emit->as, REG_RET, LOCAL_IDX_RET_VAL(emit)); + ASM_MOV_REG_LOCAL(emit->as, REG_PARENT_RET, LOCAL_IDX_RET_VAL(emit)); } ASM_EXIT(emit->as); @@ -2312,7 +2404,7 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { ASM_ARM_CC_NE, }; asm_arm_setcc_reg(emit->as, REG_RET, ccs[op - MP_BINARY_OP_LESS]); - #elif N_XTENSA + #elif N_XTENSA || N_XTENSAWIN static uint8_t ccs[6] = { ASM_XTENSA_CC_LT, 0x80 | ASM_XTENSA_CC_LT, // for GT we'll swap args @@ -2572,7 +2664,7 @@ STATIC void emit_native_return_value(emit_t *emit) { if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { // Save pointer to current stack position for caller to access return value emit_get_stack_pointer_to_reg_for_pop(emit, REG_TEMP0, 1); - emit_native_mov_state_reg(emit, offsetof(mp_code_state_t, sp) / sizeof(uintptr_t), REG_TEMP0); + emit_native_mov_state_reg(emit, OFFSETOF_CODE_STATE_SP, REG_TEMP0); // Put return type in return value slot ASM_MOV_REG_IMM(emit->as, REG_TEMP0, MP_VM_RETURN_NORMAL); @@ -2589,13 +2681,13 @@ STATIC void emit_native_return_value(emit_t *emit) { if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) { emit_pre_pop_discard(emit); if (return_vtype == VTYPE_PYOBJ) { - emit_native_mov_reg_const(emit, REG_RET, MP_F_CONST_NONE_OBJ); + emit_native_mov_reg_const(emit, REG_PARENT_RET, MP_F_CONST_NONE_OBJ); } else { ASM_MOV_REG_IMM(emit->as, REG_ARG_1, 0); } } else { vtype_kind_t vtype; - emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_RET : REG_ARG_1); + emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_PARENT_RET : REG_ARG_1); if (vtype != return_vtype) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "return expected '%q' but got '%q'", @@ -2604,15 +2696,18 @@ STATIC void emit_native_return_value(emit_t *emit) { } if (return_vtype != VTYPE_PYOBJ) { emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, return_vtype, REG_ARG_2); + #if REG_RET != REG_PARENT_RET + ASM_MOV_REG_REG(emit->as, REG_PARENT_RET, REG_RET); + #endif } } else { vtype_kind_t vtype; - emit_pre_pop_reg(emit, &vtype, REG_RET); + emit_pre_pop_reg(emit, &vtype, REG_PARENT_RET); assert(vtype == VTYPE_PYOBJ); } if (NEED_GLOBAL_EXC_HANDLER(emit)) { // Save return value for the global exception handler to use - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_RET); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_PARENT_RET); } emit_native_unwind_jump(emit, emit->exit_label, emit->exc_stack_size); emit->last_emit_was_return_value = true; @@ -2655,7 +2750,7 @@ STATIC void emit_native_yield(emit_t *emit, int kind) { // Save pointer to current stack position for caller to access yielded value emit_get_stack_pointer_to_reg_for_pop(emit, REG_TEMP0, 1); - emit_native_mov_state_reg(emit, offsetof(mp_code_state_t, sp) / sizeof(uintptr_t), REG_TEMP0); + emit_native_mov_state_reg(emit, OFFSETOF_CODE_STATE_SP, REG_TEMP0); // Put return type in return value slot ASM_MOV_REG_IMM(emit->as, REG_TEMP0, MP_VM_RETURN_YIELD); diff --git a/micropython/py/emitnx86.c b/micropython/py/emitnx86.c index 7c96c3b..f0553f0 100644 --- a/micropython/py/emitnx86.c +++ b/micropython/py/emitnx86.c @@ -1,7 +1,7 @@ // x86 specific stuff #include "py/mpconfig.h" -#include "py/runtime0.h" +#include "py/nativeglue.h" #if MICROPY_EMIT_X86 @@ -34,13 +34,11 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { [MP_F_BINARY_OP] = 3, [MP_F_BUILD_TUPLE] = 2, [MP_F_BUILD_LIST] = 2, - [MP_F_LIST_APPEND] = 2, [MP_F_BUILD_MAP] = 1, - [MP_F_STORE_MAP] = 3, - #if MICROPY_PY_BUILTINS_SET [MP_F_BUILD_SET] = 2, [MP_F_STORE_SET] = 2, - #endif + [MP_F_LIST_APPEND] = 2, + [MP_F_STORE_MAP] = 3, [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3, [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3, [MP_F_CALL_METHOD_N_KW] = 3, @@ -53,20 +51,18 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { [MP_F_IMPORT_NAME] = 3, [MP_F_IMPORT_FROM] = 2, [MP_F_IMPORT_ALL] = 1, - #if MICROPY_PY_BUILTINS_SLICE [MP_F_NEW_SLICE] = 3, - #endif [MP_F_UNPACK_SEQUENCE] = 3, [MP_F_UNPACK_EX] = 3, [MP_F_DELETE_NAME] = 1, [MP_F_DELETE_GLOBAL] = 1, - [MP_F_NEW_CELL] = 1, [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3, [MP_F_ARG_CHECK_NUM_SIG] = 3, [MP_F_SETUP_CODE_STATE] = 4, [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2, [MP_F_SMALL_INT_MODULO] = 2, [MP_F_NATIVE_YIELD_FROM] = 3, + [MP_F_SETJMP] = 1, }; #define N_X86 (1) diff --git a/micropython/py/emitnxtensawin.c b/micropython/py/emitnxtensawin.c new file mode 100644 index 0000000..38d5db1 --- /dev/null +++ b/micropython/py/emitnxtensawin.c @@ -0,0 +1,23 @@ +// Xtensa-Windowed specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_XTENSAWIN + +// this is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#define GENERIC_ASM_API_WIN (1) +#include "py/asmxtensa.h" + +// Word indices of REG_LOCAL_x in nlr_buf_t +#define NLR_BUF_IDX_LOCAL_1 (2 + 4) // a4 +#define NLR_BUF_IDX_LOCAL_2 (2 + 5) // a5 +#define NLR_BUF_IDX_LOCAL_3 (2 + 6) // a6 + +#define N_NLR_SETJMP (1) +#define N_PRELUDE_AS_BYTES_OBJ (1) +#define N_XTENSAWIN (1) +#define EXPORT_FUN(name) emit_native_xtensawin_##name +#include "py/emitnative.c" + +#endif diff --git a/micropython/py/grammar.h b/micropython/py/grammar.h index 5a5b682..ca9b5b3 100644 --- a/micropython/py/grammar.h +++ b/micropython/py/grammar.h @@ -55,7 +55,7 @@ DEF_RULE_NC(eval_input_2, and(1), tok(NEWLINE)) // varargslist: vfpdef ['=' test] (',' vfpdef ['=' test])* [',' ['*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef]] | '*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef // vfpdef: NAME -DEF_RULE_NC(decorator, and(4), tok(DEL_AT), rule(dotted_name), opt_rule(trailer_paren), tok(NEWLINE)) +DEF_RULE_NC(decorator, and(4), tok(OP_AT), rule(dotted_name), opt_rule(trailer_paren), tok(NEWLINE)) DEF_RULE_NC(decorators, one_or_more, rule(decorator)) DEF_RULE(decorated, c(decorated), and_ident(2), rule(decorators), rule(decorated_body)) #if MICROPY_PY_ASYNC_AWAIT @@ -96,7 +96,7 @@ DEF_RULE(simple_stmt_2, c(generic_all_nodes), list_with_end, rule(small_stmt), t // small_stmt: expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt // expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*) // testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [','] -// augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' +// augassign: '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' // # For normal assignments, additional restrictions enforced by the interpreter DEF_RULE_NC(small_stmt, or(8), rule(del_stmt), rule(pass_stmt), rule(flow_stmt), rule(import_stmt), rule(global_stmt), rule(nonlocal_stmt), rule(assert_stmt), rule(expr_stmt)) @@ -108,7 +108,7 @@ DEF_RULE_NC(expr_stmt_assign, and_ident(2), tok(DEL_EQUAL), rule(expr_stmt_6)) DEF_RULE_NC(expr_stmt_6, or(2), rule(yield_expr), rule(testlist_star_expr)) DEF_RULE(testlist_star_expr, c(generic_tuple), list_with_end, rule(testlist_star_expr_2), tok(DEL_COMMA)) DEF_RULE_NC(testlist_star_expr_2, or(2), rule(star_expr), rule(test)) -DEF_RULE_NC(augassign, or(12), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DEL_STAR_EQUAL), tok(DEL_SLASH_EQUAL), tok(DEL_PERCENT_EQUAL), tok(DEL_AMPERSAND_EQUAL), tok(DEL_PIPE_EQUAL), tok(DEL_CARET_EQUAL), tok(DEL_DBL_LESS_EQUAL), tok(DEL_DBL_MORE_EQUAL), tok(DEL_DBL_STAR_EQUAL), tok(DEL_DBL_SLASH_EQUAL)) +DEF_RULE_NC(augassign, or(13), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DEL_STAR_EQUAL), tok(DEL_AT_EQUAL), tok(DEL_SLASH_EQUAL), tok(DEL_PERCENT_EQUAL), tok(DEL_AMPERSAND_EQUAL), tok(DEL_PIPE_EQUAL), tok(DEL_CARET_EQUAL), tok(DEL_DBL_LESS_EQUAL), tok(DEL_DBL_MORE_EQUAL), tok(DEL_DBL_STAR_EQUAL), tok(DEL_DBL_SLASH_EQUAL)) // del_stmt: 'del' exprlist // pass_stmt: 'pass' @@ -226,7 +226,7 @@ DEF_RULE(lambdef_nocond, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(vara // and_expr: shift_expr ('&' shift_expr)* // shift_expr: arith_expr (('<<'|'>>') arith_expr)* // arith_expr: term (('+'|'-') term)* -// term: factor (('*'|'/'|'%'|'//') factor)* +// term: factor (('*'|'@'|'/'|'%'|'//') factor)* // factor: ('+'|'-'|'~') factor | power // power: atom_expr ['**' factor] // atom_expr: 'await' atom trailer* | atom trailer* @@ -249,7 +249,7 @@ DEF_RULE_NC(shift_op, or(2), tok(OP_DBL_LESS), tok(OP_DBL_MORE)) DEF_RULE(arith_expr, c(term), list, rule(term), rule(arith_op)) DEF_RULE_NC(arith_op, or(2), tok(OP_PLUS), tok(OP_MINUS)) DEF_RULE(term, c(term), list, rule(factor), rule(term_op)) -DEF_RULE_NC(term_op, or(4), tok(OP_STAR), tok(OP_SLASH), tok(OP_PERCENT), tok(OP_DBL_SLASH)) +DEF_RULE_NC(term_op, or(5), tok(OP_STAR), tok(OP_AT), tok(OP_SLASH), tok(OP_PERCENT), tok(OP_DBL_SLASH)) DEF_RULE_NC(factor, or(2), rule(factor_2), rule(power)) DEF_RULE(factor_2, c(factor_2), and_ident(2), rule(factor_op), rule(factor)) DEF_RULE_NC(factor_op, or(3), tok(OP_PLUS), tok(OP_MINUS), tok(OP_TILDE)) diff --git a/micropython/py/lexer.c b/micropython/py/lexer.c index e161700..5f8adda 100644 --- a/micropython/py/lexer.c +++ b/micropython/py/lexer.c @@ -174,7 +174,7 @@ STATIC void indent_pop(mp_lexer_t *lex) { // this means if the start of two ops are the same then they are equal til the last char STATIC const char *const tok_enc = - "()[]{},:;@~" // singles + "()[]{},:;~" // singles " >= >> >>= "*e=c*e=" // * *= ** **= @@ -185,6 +185,7 @@ STATIC const char *const tok_enc = "/e=c/e=" // / /= // //= "%e=" // % %= "^e=" // ^ ^= + "@e=" // @ @= "=e=" // = == "!."; // start of special cases: != . ... @@ -193,7 +194,7 @@ STATIC const uint8_t tok_enc_kind[] = { MP_TOKEN_DEL_PAREN_OPEN, MP_TOKEN_DEL_PAREN_CLOSE, MP_TOKEN_DEL_BRACKET_OPEN, MP_TOKEN_DEL_BRACKET_CLOSE, MP_TOKEN_DEL_BRACE_OPEN, MP_TOKEN_DEL_BRACE_CLOSE, - MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_COLON, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_DEL_AT, MP_TOKEN_OP_TILDE, + MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_COLON, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_OP_TILDE, MP_TOKEN_OP_LESS, MP_TOKEN_OP_LESS_EQUAL, MP_TOKEN_OP_DBL_LESS, MP_TOKEN_DEL_DBL_LESS_EQUAL, MP_TOKEN_OP_MORE, MP_TOKEN_OP_MORE_EQUAL, MP_TOKEN_OP_DBL_MORE, MP_TOKEN_DEL_DBL_MORE_EQUAL, @@ -205,6 +206,7 @@ STATIC const uint8_t tok_enc_kind[] = { MP_TOKEN_OP_SLASH, MP_TOKEN_DEL_SLASH_EQUAL, MP_TOKEN_OP_DBL_SLASH, MP_TOKEN_DEL_DBL_SLASH_EQUAL, MP_TOKEN_OP_PERCENT, MP_TOKEN_DEL_PERCENT_EQUAL, MP_TOKEN_OP_CARET, MP_TOKEN_DEL_CARET_EQUAL, + MP_TOKEN_OP_AT, MP_TOKEN_DEL_AT_EQUAL, MP_TOKEN_DEL_EQUAL, MP_TOKEN_OP_DBL_EQUAL, }; diff --git a/micropython/py/lexer.h b/micropython/py/lexer.h index a297091..b9f9701 100644 --- a/micropython/py/lexer.h +++ b/micropython/py/lexer.h @@ -96,26 +96,46 @@ typedef enum _mp_token_kind_t { MP_TOKEN_KW_WITH, MP_TOKEN_KW_YIELD, - MP_TOKEN_OP_PLUS, - MP_TOKEN_OP_MINUS, - MP_TOKEN_OP_STAR, - MP_TOKEN_OP_DBL_STAR, - MP_TOKEN_OP_SLASH, - MP_TOKEN_OP_DBL_SLASH, - MP_TOKEN_OP_PERCENT, + MP_TOKEN_OP_TILDE, + + // Order of these 6 matches corresponding mp_binary_op_t operator MP_TOKEN_OP_LESS, - MP_TOKEN_OP_DBL_LESS, MP_TOKEN_OP_MORE, - MP_TOKEN_OP_DBL_MORE, - MP_TOKEN_OP_AMPERSAND, - MP_TOKEN_OP_PIPE, - MP_TOKEN_OP_CARET, - MP_TOKEN_OP_TILDE, + MP_TOKEN_OP_DBL_EQUAL, MP_TOKEN_OP_LESS_EQUAL, MP_TOKEN_OP_MORE_EQUAL, - MP_TOKEN_OP_DBL_EQUAL, MP_TOKEN_OP_NOT_EQUAL, + // Order of these 13 matches corresponding mp_binary_op_t operator + MP_TOKEN_OP_PIPE, + MP_TOKEN_OP_CARET, + MP_TOKEN_OP_AMPERSAND, + MP_TOKEN_OP_DBL_LESS, + MP_TOKEN_OP_DBL_MORE, + MP_TOKEN_OP_PLUS, + MP_TOKEN_OP_MINUS, + MP_TOKEN_OP_STAR, + MP_TOKEN_OP_AT, + MP_TOKEN_OP_DBL_SLASH, + MP_TOKEN_OP_SLASH, + MP_TOKEN_OP_PERCENT, + MP_TOKEN_OP_DBL_STAR, + + // Order of these 13 matches corresponding mp_binary_op_t operator + MP_TOKEN_DEL_PIPE_EQUAL, + MP_TOKEN_DEL_CARET_EQUAL, + MP_TOKEN_DEL_AMPERSAND_EQUAL, + MP_TOKEN_DEL_DBL_LESS_EQUAL, + MP_TOKEN_DEL_DBL_MORE_EQUAL, + MP_TOKEN_DEL_PLUS_EQUAL, + MP_TOKEN_DEL_MINUS_EQUAL, + MP_TOKEN_DEL_STAR_EQUAL, + MP_TOKEN_DEL_AT_EQUAL, + MP_TOKEN_DEL_DBL_SLASH_EQUAL, + MP_TOKEN_DEL_SLASH_EQUAL, + MP_TOKEN_DEL_PERCENT_EQUAL, + MP_TOKEN_DEL_DBL_STAR_EQUAL, + MP_TOKEN_DEL_PAREN_OPEN, MP_TOKEN_DEL_PAREN_CLOSE, MP_TOKEN_DEL_BRACKET_OPEN, @@ -126,20 +146,7 @@ typedef enum _mp_token_kind_t { MP_TOKEN_DEL_COLON, MP_TOKEN_DEL_PERIOD, MP_TOKEN_DEL_SEMICOLON, - MP_TOKEN_DEL_AT, MP_TOKEN_DEL_EQUAL, - MP_TOKEN_DEL_PLUS_EQUAL, - MP_TOKEN_DEL_MINUS_EQUAL, - MP_TOKEN_DEL_STAR_EQUAL, - MP_TOKEN_DEL_SLASH_EQUAL, - MP_TOKEN_DEL_DBL_SLASH_EQUAL, - MP_TOKEN_DEL_PERCENT_EQUAL, - MP_TOKEN_DEL_AMPERSAND_EQUAL, - MP_TOKEN_DEL_PIPE_EQUAL, - MP_TOKEN_DEL_CARET_EQUAL, - MP_TOKEN_DEL_DBL_MORE_EQUAL, - MP_TOKEN_DEL_DBL_LESS_EQUAL, - MP_TOKEN_DEL_DBL_STAR_EQUAL, MP_TOKEN_DEL_MINUS_MORE, } mp_token_kind_t; @@ -177,8 +184,6 @@ void mp_lexer_to_next(mp_lexer_t *lex); // platform specific import function; must be implemented for a specific port // TODO tidy up, rename, or put elsewhere -//mp_lexer_t *mp_import_open_file(qstr mod_name); - typedef enum { MP_IMPORT_STAT_NO_EXIST, MP_IMPORT_STAT_DIR, diff --git a/micropython/py/makeqstrdata.py b/micropython/py/makeqstrdata.py index 060ebb7..7799be0 100644 --- a/micropython/py/makeqstrdata.py +++ b/micropython/py/makeqstrdata.py @@ -279,9 +279,11 @@ def parse_input_headers(infiles): # get the qstr value qstr = match.group(1) - # special case to specify control characters + # special cases to specify control characters if qstr == '\\n': qstr = '\n' + elif qstr == '\\r\\n': + qstr = '\r\n' # work out the corresponding qstr name ident = qstr_escape(qstr) @@ -337,7 +339,7 @@ def print_qstr_data(qcfgs, qstrs): print('') # add NULL qstr with no hash or data - print('QDEF(MP_QSTR_NULL, (const byte*)"%s%s" "")' % ('\\x00' * cfg_bytes_hash, '\\x00' * cfg_bytes_len)) + print('QDEF(MP_QSTRnull, (const byte*)"%s%s" "")' % ('\\x00' * cfg_bytes_hash, '\\x00' * cfg_bytes_len)) # go through each qstr and print it out for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]): diff --git a/micropython/py/makeqstrdefs.py b/micropython/py/makeqstrdefs.py index 457bdee..209e7a1 100644 --- a/micropython/py/makeqstrdefs.py +++ b/micropython/py/makeqstrdefs.py @@ -12,10 +12,6 @@ import io import os -# Blacklist of qstrings that are specially handled in further -# processing and should be ignored -QSTRING_BLACK_LIST = set(['NULL', 'number_of']) - def write_out(fname, output): if output: @@ -46,8 +42,7 @@ def process_file(f): continue for match in re_qstr.findall(line): name = match.replace('MP_QSTR_', '') - if name not in QSTRING_BLACK_LIST: - output.append('Q(' + name + ')') + output.append('Q(' + name + ')') write_out(last_fname, output) return "" diff --git a/micropython/py/mkenv.mk b/micropython/py/mkenv.mk index e3f180a..f4d1f49 100644 --- a/micropython/py/mkenv.mk +++ b/micropython/py/mkenv.mk @@ -41,6 +41,7 @@ PYTHON = python3 AS = $(CROSS_COMPILE)as CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ +GDB = $(CROSS_COMPILE)gdb LD = $(CROSS_COMPILE)ld OBJCOPY = $(CROSS_COMPILE)objcopy SIZE = $(CROSS_COMPILE)size @@ -52,10 +53,13 @@ CXX += -m32 LD += -m32 endif +MAKE_MANIFEST = $(PYTHON) $(TOP)/tools/makemanifest.py MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py MPY_CROSS = $(TOP)/mpy-cross/mpy-cross MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py +MPY_LIB_DIR = $(TOP)/../micropython-lib + all: .PHONY: all diff --git a/micropython/py/mkrules.mk b/micropython/py/mkrules.mk index 184d99b..68da3e7 100644 --- a/micropython/py/mkrules.mk +++ b/micropython/py/mkrules.mk @@ -30,7 +30,6 @@ $(BUILD)/%.o: %.s $(ECHO) "AS $<" $(Q)$(AS) -o $@ $< -ifeq ($(BUILD_VERBOSE),1) define compile_c $(ECHO) "CC $<" $(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< @@ -42,18 +41,6 @@ $(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ $(RM) -f $(@:.o=.d) endef -else -define compile_c -$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< -@# The following fixes the dependency file. -@# See http://make.paulandlesley.org/autodep.html for details. -@# Regex adjusted from the above to play better with Windows paths, etc. -@$(CP) $(@:.o=.d) $(@:.o=.P); \ - $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ - $(RM) -f $(@:.o=.d) -endef -endif vpath %.c . $(TOP) $(USER_C_MODULES) $(BUILD)/%.o: %.c @@ -66,7 +53,7 @@ vpath %.c . $(TOP) $(USER_C_MODULES) $(BUILD)/%.pp: %.c $(ECHO) "PreProcess $<" - $(Q)$(CC) $(CFLAGS) -E -Wp,-C,-dD,-dI -o $@ $< + $(Q)$(CPP) $(CFLAGS) -Wp,-C,-dD,-dI -o $@ $< # The following rule uses | to create an order only prerequisite. Order only # prerequisites only get built if they don't exist. They don't cause timestamp @@ -83,7 +70,8 @@ $(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h # - if anything in QSTR_GLOBAL_DEPENDENCIES is newer, then process all source files ($^) # - else, if list of newer prerequisites ($?) is not empty, then process just these ($?) # - else, process all source files ($^) [this covers "make -B" which can set $? to empty] -$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h +# See more information about this process in docs/develop/qstr.rst. +$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(QSTR_GLOBAL_REQUIREMENTS) $(ECHO) "GEN $@" $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) >$(HEADER_BUILD)/qstr.i.last @@ -102,32 +90,42 @@ $(QSTR_DEFS_COLLECTED): $(HEADER_BUILD)/qstr.split # object directories (but only for existence), and the object directories # will be created if they don't exist. OBJ_DIRS = $(sort $(dir $(OBJ))) -# LoBo: changed $(OBJ): | $(OBJ_DIRS) -$(OBJ): $(OBJ_DIRS) +$(OBJ): | $(OBJ_DIRS) $(OBJ_DIRS): $(MKDIR) -p $@ $(HEADER_BUILD): $(MKDIR) -p $@ +ifneq ($(FROZEN_MANIFEST),) +# to build frozen_content.c from a manifest +$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h + $(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) $(FROZEN_MANIFEST) + ifneq ($(FROZEN_DIR),) +$(error FROZEN_DIR cannot be used in conjunction with FROZEN_MANIFEST) +endif + +ifneq ($(FROZEN_MPY_DIR),) +$(error FROZEN_MPY_DIR cannot be used in conjunction with FROZEN_MANIFEST) +endif +endif + +ifneq ($(FROZEN_DIR),) +$(info Warning: FROZEN_DIR is deprecated in favour of FROZEN_MANIFEST) $(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS) $(ECHO) "GEN $@" $(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@ endif ifneq ($(FROZEN_MPY_DIR),) -# to build the MicroPython cross compiler -# LoBo: 'mpy-cross' is built from 'BUILD.sh' -#$(TOP)/mpy-cross/mpy-cross: $(TOP)/py/*.[ch] $(TOP)/mpy-cross/*.[ch] $(TOP)/ports/windows/fmode.c -# $(Q)$(MAKE) -C $(TOP)/mpy-cross - +$(info Warning: FROZEN_MPY_DIR is deprecated in favour of FROZEN_MANIFEST) # make a list of all the .py files that need compiling and freezing FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) # to build .mpy files from .py files -$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py $(TOP)/mpy-cross/mpy-cross +$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py @$(ECHO) "MPY $<" $(Q)$(MKDIR) -p $(dir $@) $(Q)$(MPY_CROSS) -o $@ -s $(<:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $< @@ -161,6 +159,13 @@ clean-prog: .PHONY: clean-prog endif +submodules: + $(ECHO) "Updating submodules: $(GIT_SUBMODULES)" +ifneq ($(GIT_SUBMODULES),) + $(Q)git submodule update --init $(addprefix $(TOP)/,$(GIT_SUBMODULES)) +endif +.PHONY: submodules + LIBMICROPYTHON = libmicropython.a # We can execute extra commands after library creation using diff --git a/micropython/py/modarray.c b/micropython/py/modarray.c index de84fc8..b459a83 100644 --- a/micropython/py/modarray.c +++ b/micropython/py/modarray.c @@ -29,17 +29,17 @@ #if MICROPY_PY_ARRAY STATIC const mp_rom_map_elem_t mp_module_array_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_array) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uarray) }, { MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_type_array) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_array_globals, mp_module_array_globals_table); -const mp_obj_module_t mp_module_array = { +const mp_obj_module_t mp_module_uarray = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_array_globals, }; -MP_REGISTER_MODULE(MP_QSTR_array, mp_module_array, MICROPY_PY_ARRAY); +MP_REGISTER_MODULE(MP_QSTR_uarray, mp_module_uarray, MICROPY_PY_ARRAY); #endif diff --git a/micropython/py/modio.c b/micropython/py/modio.c index 0f4a432..94ef5d4 100644 --- a/micropython/py/modio.c +++ b/micropython/py/modio.c @@ -208,15 +208,8 @@ STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { // package parameter being None, the path_in is interpreted as a // raw path. if (package_in != mp_const_none) { - mp_obj_t args[5]; - args[0] = package_in; - args[1] = mp_const_none; // TODO should be globals - args[2] = mp_const_none; // TODO should be locals - args[3] = mp_const_true; // Pass sentinel "non empty" value to force returning of leaf module - args[4] = MP_OBJ_NEW_SMALL_INT(0); - - // TODO lookup __import__ and call that instead of going straight to builtin implementation - mp_obj_t pkg = mp_builtin___import__(5, args); + // Pass "True" as sentinel value in fromlist to force returning of leaf module + mp_obj_t pkg = mp_import_name(mp_obj_str_get_qstr(package_in), mp_const_true, MP_OBJ_NEW_SMALL_INT(0)); mp_obj_t dest[2]; mp_load_method_maybe(pkg, MP_QSTR___path__, dest); diff --git a/micropython/py/modmath.c b/micropython/py/modmath.c index d106f24..35bb44b 100644 --- a/micropython/py/modmath.c +++ b/micropython/py/modmath.c @@ -171,6 +171,42 @@ MATH_FUN_1(lgamma, lgamma) #endif //TODO: fsum +#if MICROPY_PY_MATH_ISCLOSE +STATIC mp_obj_t mp_math_isclose(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_a, ARG_b, ARG_rel_tol, ARG_abs_tol }; + static const mp_arg_t allowed_args[] = { + {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_rel_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_abs_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(0)}}, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + const mp_float_t a = mp_obj_get_float(args[ARG_a].u_obj); + const mp_float_t b = mp_obj_get_float(args[ARG_b].u_obj); + const mp_float_t rel_tol = args[ARG_rel_tol].u_obj == MP_OBJ_NULL + ? (mp_float_t)1e-9 : mp_obj_get_float(args[ARG_rel_tol].u_obj); + const mp_float_t abs_tol = mp_obj_get_float(args[ARG_abs_tol].u_obj); + if (rel_tol < (mp_float_t)0.0 || abs_tol < (mp_float_t)0.0) { + math_error(); + } + if (a == b) { + return mp_const_true; + } + const mp_float_t difference = MICROPY_FLOAT_C_FUN(fabs)(a - b); + if (isinf(difference)) { // Either a or b is inf + return mp_const_false; + } + if ((difference <= abs_tol) || + (difference <= MICROPY_FLOAT_C_FUN(fabs)(rel_tol * a)) || + (difference <= MICROPY_FLOAT_C_FUN(fabs)(rel_tol * b))) { + return mp_const_true; + } + return mp_const_false; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_math_isclose_obj, 2, mp_math_isclose); +#endif + // Function that takes a variable number of arguments // log(x[, base]) @@ -335,6 +371,9 @@ STATIC const mp_rom_map_elem_t mp_module_math_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_math_isfinite_obj) }, { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_math_isinf_obj) }, { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_math_isnan_obj) }, + #if MICROPY_PY_MATH_ISCLOSE + { MP_ROM_QSTR(MP_QSTR_isclose), MP_ROM_PTR(&mp_math_isclose_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_trunc), MP_ROM_PTR(&mp_math_trunc_obj) }, { MP_ROM_QSTR(MP_QSTR_radians), MP_ROM_PTR(&mp_math_radians_obj) }, { MP_ROM_QSTR(MP_QSTR_degrees), MP_ROM_PTR(&mp_math_degrees_obj) }, diff --git a/micropython/py/modmicropython.c b/micropython/py/modmicropython.c index 3e54509..99d0d92 100644 --- a/micropython/py/modmicropython.c +++ b/micropython/py/modmicropython.c @@ -154,7 +154,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd #if MICROPY_ENABLE_SCHEDULER STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) { if (!mp_sched_schedule(function, arg)) { - mp_raise_msg(&mp_type_RuntimeError, "schedule stack full"); + mp_raise_msg(&mp_type_RuntimeError, "schedule queue full"); } return mp_const_none; } diff --git a/micropython/py/modstruct.c b/micropython/py/modstruct.c index 8617a8e..36af426 100644 --- a/micropython/py/modstruct.c +++ b/micropython/py/modstruct.c @@ -97,7 +97,7 @@ STATIC size_t calc_size_items(const char *fmt, size_t *total_sz) { size += cnt; } else { total_cnt += cnt; - mp_uint_t align; + size_t align; size_t sz = mp_binary_get_size(fmt_type, *fmt, &align); while (cnt--) { // Apply alignment @@ -146,6 +146,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { } p += offset; } + byte *p_base = p; // Check that the input buffer is big enough to unpack all the values if (p + total_sz > end_p) { @@ -164,7 +165,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { res->items[i++] = item; } else { while (cnt--) { - item = mp_binary_get_val(fmt_type, *fmt, &p); + item = mp_binary_get_val(fmt_type, *fmt, p_base, &p); res->items[i++] = item; } } @@ -179,6 +180,7 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, c const char *fmt = mp_obj_str_get_str(fmt_in); char fmt_type = get_fmt_type(&fmt); + byte *p_base = p; size_t i; for (i = 0; i < n_args;) { mp_uint_t cnt = 1; @@ -203,7 +205,7 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, c } else { // If we run out of args then we just finish; CPython would raise struct.error while (cnt-- && i < n_args) { - mp_binary_set_val(fmt_type, *fmt, args[i++], &p); + mp_binary_set_val(fmt_type, *fmt, args[i++], p_base, &p); } } fmt++; diff --git a/micropython/py/modsys.c b/micropython/py/modsys.c index 71c9ce6..5dfc3ff 100644 --- a/micropython/py/modsys.c +++ b/micropython/py/modsys.c @@ -35,6 +35,12 @@ #include "py/stream.h" #include "py/smallint.h" #include "py/runtime.h" +#include "py/persistentcode.h" + +#if MICROPY_PY_SYS_SETTRACE +#include "py/objmodule.h" +#include "py/profile.h" +#endif #if MICROPY_PY_SYS @@ -62,22 +68,36 @@ STATIC const mp_obj_tuple_t mp_sys_implementation_version_info_obj = { 3, { I(MICROPY_VERSION_MAJOR), I(MICROPY_VERSION_MINOR), I(MICROPY_VERSION_MICRO) } }; +#if MICROPY_PERSISTENT_CODE_LOAD +#define SYS_IMPLEMENTATION_ELEMS \ + MP_ROM_QSTR(MP_QSTR_micropython), \ + MP_ROM_PTR(&mp_sys_implementation_version_info_obj), \ + MP_ROM_INT(MPY_FILE_HEADER_INT) +#else +#define SYS_IMPLEMENTATION_ELEMS \ + MP_ROM_QSTR(MP_QSTR_micropython), \ + MP_ROM_PTR(&mp_sys_implementation_version_info_obj) +#endif #if MICROPY_PY_ATTRTUPLE -STATIC const qstr impl_fields[] = { MP_QSTR_name, MP_QSTR_version }; +STATIC const qstr impl_fields[] = { + MP_QSTR_name, + MP_QSTR_version, + #if MICROPY_PERSISTENT_CODE_LOAD + MP_QSTR_mpy, + #endif +}; STATIC MP_DEFINE_ATTRTUPLE( mp_sys_implementation_obj, impl_fields, - 2, - MP_ROM_QSTR(MP_QSTR_micropython), - MP_ROM_PTR(&mp_sys_implementation_version_info_obj) + 2 + MICROPY_PERSISTENT_CODE_LOAD, + SYS_IMPLEMENTATION_ELEMS ); #else STATIC const mp_rom_obj_tuple_t mp_sys_implementation_obj = { {&mp_type_tuple}, - 2, + 2 + MICROPY_PERSISTENT_CODE_LOAD, { - MP_ROM_QSTR(MP_QSTR_micropython), - MP_ROM_PTR(&mp_sys_implementation_version_info_obj), + SYS_IMPLEMENTATION_ELEMS } }; #endif @@ -147,6 +167,24 @@ STATIC mp_obj_t mp_sys_getsizeof(mp_obj_t obj) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof); #endif +#if MICROPY_PY_SYS_ATEXIT +// atexit(callback): Callback is called when sys.exit is called. +STATIC mp_obj_t mp_sys_atexit(mp_obj_t obj) { + mp_obj_t old = MP_STATE_VM(sys_exitfunc); + MP_STATE_VM(sys_exitfunc) = obj; + return old; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_atexit_obj, mp_sys_atexit); +#endif + +#if MICROPY_PY_SYS_SETTRACE +// settrace(tracefunc): Set the system’s trace function. +STATIC mp_obj_t mp_sys_settrace(mp_obj_t obj) { + return mp_prof_settrace(obj); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_settrace_obj, mp_sys_settrace); +#endif // MICROPY_PY_SYS_SETTRACE + // Lobo: support for two MicroPython instances running // sys.path, sys.argv and sys.modules are now FUNCTIONS sys.path(), sys.argv() and sys.modules() //------------------------------ @@ -205,6 +243,10 @@ STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mp_sys_exit_obj) }, #endif + #if MICROPY_PY_SYS_SETTRACE + { MP_ROM_QSTR(MP_QSTR_settrace), MP_ROM_PTR(&mp_sys_settrace_obj) }, + #endif + #if MICROPY_PY_SYS_STDFILES { MP_ROM_QSTR(MP_QSTR_stdin), MP_ROM_PTR(&mp_sys_stdin_obj) }, { MP_ROM_QSTR(MP_QSTR_stdout), MP_ROM_PTR(&mp_sys_stdout_obj) }, @@ -226,6 +268,9 @@ STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = { */ { MP_ROM_QSTR(MP_QSTR_print_exception), MP_ROM_PTR(&mp_sys_print_exception_obj) }, + #if MICROPY_PY_SYS_ATEXIT + { MP_ROM_QSTR(MP_QSTR_atexit), MP_ROM_PTR(&mp_sys_atexit_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table); diff --git a/micropython/py/moduerrno.c b/micropython/py/moduerrno.c index de66c94..0e0a3f0 100644 --- a/micropython/py/moduerrno.c +++ b/micropython/py/moduerrno.c @@ -104,7 +104,7 @@ qstr mp_errno_to_str(mp_obj_t errno_val) { // We have the errorcode dict so can do a lookup using the hash map mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&errorcode_dict.map, errno_val, MP_MAP_LOOKUP); if (elem == NULL) { - return MP_QSTR_NULL; + return MP_QSTRnull; } else { return MP_OBJ_QSTR_VALUE(elem->value); } @@ -115,7 +115,7 @@ qstr mp_errno_to_str(mp_obj_t errno_val) { return MP_OBJ_QSTR_VALUE(mp_module_uerrno_globals_table[i].key); } } - return MP_QSTR_NULL; + return MP_QSTRnull; #endif } diff --git a/micropython/py/mpconfig.h b/micropython/py/mpconfig.h index 219f8de..1e786f7 100644 --- a/micropython/py/mpconfig.h +++ b/micropython/py/mpconfig.h @@ -28,7 +28,7 @@ // Current version of MicroPython #define MICROPY_VERSION_MAJOR 1 -#define MICROPY_VERSION_MINOR 11 +#define MICROPY_VERSION_MINOR 12 #define MICROPY_VERSION_MICRO 0 // Combined version as a 32-bit number for convenience @@ -323,12 +323,23 @@ #define MICROPY_EMIT_INLINE_XTENSA (0) #endif +// Whether to emit Xtensa-Windowed native code +#ifndef MICROPY_EMIT_XTENSAWIN +#define MICROPY_EMIT_XTENSAWIN (0) +#endif + // Convenience definition for whether any native emitter is enabled -#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA) +#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA || MICROPY_EMIT_XTENSAWIN) + +// Select prelude-as-bytes-object for certain emitters +#define MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ (MICROPY_EMIT_XTENSAWIN) // Convenience definition for whether any inline assembler emitter is enabled #define MICROPY_EMIT_INLINE_ASM (MICROPY_EMIT_INLINE_THUMB || MICROPY_EMIT_INLINE_XTENSA) +// Convenience definition for whether any native or inline assembler emitter is enabled +#define MICROPY_EMIT_MACHINE_CODE (MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM) + /*****************************************************************************/ /* Compiler configuration */ @@ -338,6 +349,7 @@ #endif // Whether the compiler is dynamically configurable (ie at runtime) +// This will disable the ability to execute native/viper code #ifndef MICROPY_DYNAMIC_COMPILER #define MICROPY_DYNAMIC_COMPILER (0) #endif @@ -1075,6 +1087,11 @@ typedef double mp_float_t; #define MICROPY_PY_MATH_FACTORIAL (0) #endif +// Whether to provide math.isclose function +#ifndef MICROPY_PY_MATH_ISCLOSE +#define MICROPY_PY_MATH_ISCLOSE (0) +#endif + // Whether to provide "cmath" module #ifndef MICROPY_PY_CMATH #define MICROPY_PY_CMATH (0) @@ -1157,6 +1174,16 @@ typedef double mp_float_t; #define MICROPY_PY_SYS_EXIT (1) #endif +// Whether to provide "sys.atexit" function (MicroPython extension) +#ifndef MICROPY_PY_SYS_ATEXIT +#define MICROPY_PY_SYS_ATEXIT (0) +#endif + +// Whether to provide "sys.settrace" function +#ifndef MICROPY_PY_SYS_SETTRACE +#define MICROPY_PY_SYS_SETTRACE (0) +#endif + // Whether to provide "sys.getsizeof" function #ifndef MICROPY_PY_SYS_GETSIZEOF #define MICROPY_PY_SYS_GETSIZEOF (0) @@ -1245,6 +1272,10 @@ typedef double mp_float_t; #define MICROPY_PY_URE (0) #endif +#ifndef MICROPY_PY_URE_DEBUG +#define MICROPY_PY_URE_DEBUG (0) +#endif + #ifndef MICROPY_PY_URE_MATCH_GROUPS #define MICROPY_PY_URE_MATCH_GROUPS (0) #endif @@ -1361,11 +1392,6 @@ typedef double mp_float_t; #define MICROPY_PORT_BUILTIN_MODULES #endif -// Any module weak links - see objmodule.c:mp_builtin_module_weak_links_table. -#ifndef MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS -#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS -#endif - // Additional constant definitions for the compiler - see compile.c:mp_constants_table. #ifndef MICROPY_PORT_CONSTANTS #define MICROPY_PORT_CONSTANTS @@ -1513,6 +1539,15 @@ typedef double mp_float_t; #define MP_UNLIKELY(x) __builtin_expect((x), 0) #endif +// To annotate that code is unreachable +#ifndef MP_UNREACHABLE +#if defined(__GNUC__) +#define MP_UNREACHABLE __builtin_unreachable(); +#else +#define MP_UNREACHABLE for (;;); +#endif +#endif + #ifndef MP_HTOBE16 #if MP_ENDIANNESS_LITTLE # define MP_HTOBE16(x) ((uint16_t)( (((x) & 0xff) << 8) | (((x) >> 8) & 0xff) )) @@ -1544,4 +1579,14 @@ typedef double mp_float_t; # define MP_WARN_CAT(x) (NULL) #endif +// Feature dependency check. +#if MICROPY_PY_SYS_SETTRACE +#if !MICROPY_PERSISTENT_CODE_SAVE +#error "MICROPY_PY_SYS_SETTRACE requires MICROPY_PERSISTENT_CODE_SAVE to be enabled" +#endif +#if MICROPY_COMP_CONST +#error "MICROPY_PY_SYS_SETTRACE requires MICROPY_COMP_CONST to be disabled" +#endif +#endif + #endif // MICROPY_INCLUDED_PY_MPCONFIG_H diff --git a/micropython/py/mphal.h b/micropython/py/mphal.h index 92de01d..66d8070 100644 --- a/micropython/py/mphal.h +++ b/micropython/py/mphal.h @@ -34,6 +34,10 @@ #include #endif +#ifndef mp_hal_stdio_poll +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags); +#endif + #ifndef mp_hal_stdin_rx_chr int mp_hal_stdin_rx_chr(void); #endif diff --git a/micropython/py/mpstate.c b/micropython/py/mpstate.c index d55e701..6c75fed 100644 --- a/micropython/py/mpstate.c +++ b/micropython/py/mpstate.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2014 Damien P. George + * Copyright (c) 2019 LoBo (https://github.com/loboris) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/micropython/py/mpstate.h b/micropython/py/mpstate.h index f134e36..9c42f2d 100644 --- a/micropython/py/mpstate.h +++ b/micropython/py/mpstate.h @@ -48,6 +48,7 @@ typedef struct mp_dynamic_compiler_t { bool opt_cache_map_lookup_in_bytecode; bool py_builtins_str_unicode; uint8_t native_arch; + uint8_t nlr_buf_num_regs; } mp_dynamic_compiler_t; extern mp_dynamic_compiler_t mp_dynamic_compiler; #endif @@ -142,7 +143,7 @@ typedef struct _mp_state_vm_t { volatile mp_obj_t mp_pending_exception; #if MICROPY_ENABLE_SCHEDULER - mp_sched_item_t sched_stack[MICROPY_SCHEDULER_DEPTH]; + mp_sched_item_t sched_queue[MICROPY_SCHEDULER_DEPTH]; #endif // current exception being handled, for sys.exc_info() @@ -150,6 +151,11 @@ typedef struct _mp_state_vm_t { mp_obj_base_t *cur_exception; #endif + #if MICROPY_PY_SYS_ATEXIT + // exposed through sys.atexit function + mp_obj_t sys_exitfunc; + #endif + // dictionary for the __main__ module mp_obj_dict_t dict_main; @@ -184,6 +190,10 @@ typedef struct _mp_state_vm_t { struct _mp_vfs_mount_t *vfs_mount_table; #endif + #if MICROPY_PY_BLUETOOTH + mp_obj_t bluetooth; + #endif + // // END ROOT POINTER SECTION //////////////////////////////////////////////////////////// @@ -201,6 +211,9 @@ typedef struct _mp_state_vm_t { #if MICROPY_ENABLE_COMPILER mp_uint_t mp_optimise_value; + #if MICROPY_EMIT_NATIVE + uint8_t default_emit_opt; // one of MP_EMIT_OPT_xxx + #endif #endif // size of the emergency exception buf, if it's dynamically allocated @@ -245,6 +258,12 @@ typedef struct _mp_state_thread_t { mp_obj_dict_t *dict_globals; nlr_buf_t *nlr_top; + + #if MICROPY_PY_SYS_SETTRACE + mp_obj_t prof_trace_callback; + bool prof_callback_is_executing; + struct _mp_code_state_t *current_code_state; + #endif } __attribute__((aligned(8))) mp_state_thread_t; // This structure combines the above 3 structures. diff --git a/micropython/py/nativeglue.c b/micropython/py/nativeglue.c index c810f31..1a7f92f 100644 --- a/micropython/py/nativeglue.c +++ b/micropython/py/nativeglue.c @@ -24,14 +24,15 @@ * THE SOFTWARE. */ +#include #include #include #include #include "py/runtime.h" #include "py/smallint.h" -#include "py/emitglue.h" -#include "py/bc.h" +#include "py/nativeglue.h" +#include "py/gc.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_printf DEBUG_printf @@ -65,7 +66,7 @@ mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) { case MP_NATIVE_TYPE_UINT: return mp_obj_get_int_truncated(obj); default: { // cast obj to a pointer mp_buffer_info_t bufinfo; - if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_RW)) { + if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_READ)) { return (mp_uint_t)bufinfo.buf; } else { // assume obj is an integer that represents an address @@ -77,7 +78,7 @@ mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) { #endif -#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM +#if MICROPY_EMIT_MACHINE_CODE // convert a native value to a MicroPython object based on type mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { @@ -95,9 +96,32 @@ mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) { #endif -#if MICROPY_EMIT_NATIVE +#if MICROPY_EMIT_NATIVE && !MICROPY_DYNAMIC_COMPILER + +#if !MICROPY_PY_BUILTINS_SET +mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) { + (void)n_args; + (void)items; + mp_raise_msg(&mp_type_RuntimeError, "set unsupported"); +} + +void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) { + (void)self_in; + (void)item; + mp_raise_msg(&mp_type_RuntimeError, "set unsupported"); +} +#endif -mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals) { +#if !MICROPY_PY_BUILTINS_SLICE +mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) { + (void)ostart; + (void)ostop; + (void)ostep; + mp_raise_msg(&mp_type_RuntimeError, "slice unsupported"); +} +#endif + +STATIC mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals) { if (new_globals == NULL) { // Globals were the originally the same so don't restore them return NULL; @@ -113,13 +137,13 @@ mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals) { // wrapper that accepts n_args and n_kw in one argument // (native emitter can only pass at most 3 arguments to a function) -mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args) { +STATIC mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args) { return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args); } // wrapper that makes raise obj and raises it // END_FINALLY opcode requires that we don't raise if o==None -void mp_native_raise(mp_obj_t o) { +STATIC void mp_native_raise(mp_obj_t o) { if (o != MP_OBJ_NULL && o != mp_const_none) { nlr_raise(mp_make_raise_obj(o)); } @@ -187,8 +211,50 @@ STATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *re return false; } +#if MICROPY_PY_BUILTINS_FLOAT + +STATIC mp_obj_t mp_obj_new_float_from_f(float f) { + return mp_obj_new_float((mp_float_t)f); +} + +STATIC mp_obj_t mp_obj_new_float_from_d(double d) { + return mp_obj_new_float((mp_float_t)d); +} + +STATIC float mp_obj_get_float_to_f(mp_obj_t o) { + return (float)mp_obj_get_float(o); +} + +STATIC double mp_obj_get_float_to_d(mp_obj_t o) { + return (double)mp_obj_get_float(o); +} + +#else + +STATIC mp_obj_t mp_obj_new_float_from_f(float f) { + (void)f; + mp_raise_msg(&mp_type_RuntimeError, "float unsupported"); +} + +STATIC mp_obj_t mp_obj_new_float_from_d(double d) { + (void)d; + mp_raise_msg(&mp_type_RuntimeError, "float unsupported"); +} + +STATIC float mp_obj_get_float_to_f(mp_obj_t o) { + (void)o; + mp_raise_msg(&mp_type_RuntimeError, "float unsupported"); +} + +STATIC double mp_obj_get_float_to_d(mp_obj_t o) { + (void)o; + mp_raise_msg(&mp_type_RuntimeError, "float unsupported"); +} + +#endif + // these must correspond to the respective enum in runtime0.h -const void *const mp_fun_table[MP_F_NUMBER_OF] = { +const mp_fun_table_t mp_fun_table = { &mp_const_none_obj, &mp_const_false_obj, &mp_const_true_obj, @@ -210,45 +276,74 @@ const void *const mp_fun_table[MP_F_NUMBER_OF] = { mp_binary_op, mp_obj_new_tuple, mp_obj_new_list, - mp_obj_list_append, mp_obj_new_dict, - mp_obj_dict_store, -#if MICROPY_PY_BUILTINS_SET - mp_obj_set_store, mp_obj_new_set, -#endif + mp_obj_set_store, + mp_obj_list_append, + mp_obj_dict_store, mp_make_function_from_raw_code, mp_native_call_function_n_kw, mp_call_method_n_kw, mp_call_method_n_kw_var, mp_native_getiter, mp_native_iternext, + #if MICROPY_NLR_SETJMP + nlr_push_tail, + #else nlr_push, + #endif nlr_pop, mp_native_raise, mp_import_name, mp_import_from, mp_import_all, -#if MICROPY_PY_BUILTINS_SLICE mp_obj_new_slice, -#endif mp_unpack_sequence, mp_unpack_ex, mp_delete_name, mp_delete_global, - mp_obj_new_cell, mp_make_closure_from_raw_code, mp_arg_check_num_sig, mp_setup_code_state, mp_small_int_floor_divide, mp_small_int_modulo, mp_native_yield_from, + #if MICROPY_NLR_SETJMP + setjmp, + #else + NULL, + #endif + // Additional entries for dynamic runtime, starts at index 50 + memset, + memmove, + gc_realloc, + mp_printf, + mp_vprintf, + mp_raise_msg, + mp_obj_get_type, + mp_obj_new_str, + mp_obj_new_bytes, + mp_obj_new_bytearray_by_ref, + mp_obj_new_float_from_f, + mp_obj_new_float_from_d, + mp_obj_get_float_to_f, + mp_obj_get_float_to_d, + mp_get_buffer_raise, + mp_get_stream_raise, + &mp_plat_print, + &mp_type_type, + &mp_type_str, + &mp_type_list, + &mp_type_dict, + &mp_type_fun_builtin_0, + &mp_type_fun_builtin_1, + &mp_type_fun_builtin_2, + &mp_type_fun_builtin_3, + &mp_type_fun_builtin_var, + &mp_stream_read_obj, + &mp_stream_readinto_obj, + &mp_stream_unbuffered_readline_obj, + &mp_stream_write_obj, }; -/* -void mp_f_vector(mp_fun_kind_t fun_kind) { - (mp_f_table[fun_kind])(); -} -*/ - #endif // MICROPY_EMIT_NATIVE diff --git a/micropython/py/nativeglue.h b/micropython/py/nativeglue.h new file mode 100644 index 0000000..021e7a8 --- /dev/null +++ b/micropython/py/nativeglue.h @@ -0,0 +1,177 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_NATIVEGLUE_H +#define MICROPY_INCLUDED_PY_NATIVEGLUE_H + +#include +#include "py/obj.h" +#include "py/persistentcode.h" +#include "py/stream.h" + +typedef enum { + MP_F_CONST_NONE_OBJ = 0, + MP_F_CONST_FALSE_OBJ, + MP_F_CONST_TRUE_OBJ, + MP_F_CONVERT_OBJ_TO_NATIVE, + MP_F_CONVERT_NATIVE_TO_OBJ, + MP_F_NATIVE_SWAP_GLOBALS, + MP_F_LOAD_NAME, + MP_F_LOAD_GLOBAL, + MP_F_LOAD_BUILD_CLASS, + MP_F_LOAD_ATTR, + MP_F_LOAD_METHOD, + MP_F_LOAD_SUPER_METHOD, + MP_F_STORE_NAME, + MP_F_STORE_GLOBAL, + MP_F_STORE_ATTR, + MP_F_OBJ_SUBSCR, + MP_F_OBJ_IS_TRUE, + MP_F_UNARY_OP, + MP_F_BINARY_OP, + MP_F_BUILD_TUPLE, + MP_F_BUILD_LIST, + MP_F_BUILD_MAP, + MP_F_BUILD_SET, + MP_F_STORE_SET, + MP_F_LIST_APPEND, + MP_F_STORE_MAP, + MP_F_MAKE_FUNCTION_FROM_RAW_CODE, + MP_F_NATIVE_CALL_FUNCTION_N_KW, + MP_F_CALL_METHOD_N_KW, + MP_F_CALL_METHOD_N_KW_VAR, + MP_F_NATIVE_GETITER, + MP_F_NATIVE_ITERNEXT, + MP_F_NLR_PUSH, + MP_F_NLR_POP, + MP_F_NATIVE_RAISE, + MP_F_IMPORT_NAME, + MP_F_IMPORT_FROM, + MP_F_IMPORT_ALL, + MP_F_NEW_SLICE, + MP_F_UNPACK_SEQUENCE, + MP_F_UNPACK_EX, + MP_F_DELETE_NAME, + MP_F_DELETE_GLOBAL, + MP_F_MAKE_CLOSURE_FROM_RAW_CODE, + MP_F_ARG_CHECK_NUM_SIG, + MP_F_SETUP_CODE_STATE, + MP_F_SMALL_INT_FLOOR_DIVIDE, + MP_F_SMALL_INT_MODULO, + MP_F_NATIVE_YIELD_FROM, + MP_F_SETJMP, + MP_F_NUMBER_OF, +} mp_fun_kind_t; + +typedef struct _mp_fun_table_t { + mp_const_obj_t const_none; + mp_const_obj_t const_false; + mp_const_obj_t const_true; + mp_uint_t (*native_from_obj)(mp_obj_t obj, mp_uint_t type); + mp_obj_t (*native_to_obj)(mp_uint_t val, mp_uint_t type); + mp_obj_dict_t *(*swap_globals)(mp_obj_dict_t *new_globals); + mp_obj_t (*load_name)(qstr qst); + mp_obj_t (*load_global)(qstr qst); + mp_obj_t (*load_build_class)(void); + mp_obj_t (*load_attr)(mp_obj_t base, qstr attr); + void (*load_method)(mp_obj_t base, qstr attr, mp_obj_t *dest); + void (*load_super_method)(qstr attr, mp_obj_t *dest); + void (*store_name)(qstr qst, mp_obj_t obj); + void (*store_global)(qstr qst, mp_obj_t obj); + void (*store_attr)(mp_obj_t base, qstr attr, mp_obj_t val); + mp_obj_t (*obj_subscr)(mp_obj_t base, mp_obj_t index, mp_obj_t val); + bool (*obj_is_true)(mp_obj_t arg); + mp_obj_t (*unary_op)(mp_unary_op_t op, mp_obj_t arg); + mp_obj_t (*binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs); + mp_obj_t (*new_tuple)(size_t n, const mp_obj_t *items); + mp_obj_t (*new_list)(size_t n, mp_obj_t *items); + mp_obj_t (*new_dict)(size_t n_args); + mp_obj_t (*new_set)(size_t n_args, mp_obj_t *items); + void (*set_store)(mp_obj_t self_in, mp_obj_t item); + mp_obj_t (*list_append)(mp_obj_t self_in, mp_obj_t arg); + mp_obj_t (*dict_store)(mp_obj_t self_in, mp_obj_t key, mp_obj_t value); + mp_obj_t (*make_function_from_raw_code)(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args); + mp_obj_t (*call_function_n_kw)(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args); + mp_obj_t (*call_method_n_kw)(size_t n_args, size_t n_kw, const mp_obj_t *args); + mp_obj_t (*call_method_n_kw_var)(bool have_self, size_t n_args_n_kw, const mp_obj_t *args); + mp_obj_t (*getiter)(mp_obj_t obj, mp_obj_iter_buf_t *iter); + mp_obj_t (*iternext)(mp_obj_iter_buf_t *iter); + unsigned int (*nlr_push)(nlr_buf_t *); + void (*nlr_pop)(void); + void (*raise)(mp_obj_t o); + mp_obj_t (*import_name)(qstr name, mp_obj_t fromlist, mp_obj_t level); + mp_obj_t (*import_from)(mp_obj_t module, qstr name); + void (*import_all)(mp_obj_t module); + mp_obj_t (*new_slice)(mp_obj_t start, mp_obj_t stop, mp_obj_t step); + void (*unpack_sequence)(mp_obj_t seq, size_t num, mp_obj_t *items); + void (*unpack_ex)(mp_obj_t seq, size_t num, mp_obj_t *items); + void (*delete_name)(qstr qst); + void (*delete_global)(qstr qst); + mp_obj_t (*make_closure_from_raw_code)(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args); + void (*arg_check_num_sig)(size_t n_args, size_t n_kw, uint32_t sig); + void (*setup_code_state)(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); + mp_int_t (*small_int_floor_divide)(mp_int_t num, mp_int_t denom); + mp_int_t (*small_int_modulo)(mp_int_t dividend, mp_int_t divisor); + bool (*yield_from)(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *ret_value); + void *setjmp; + // Additional entries for dynamic runtime, starts at index 50 + void *(*memset_)(void *s, int c, size_t n); + void *(*memmove_)(void *dest, const void *src, size_t n); + void *(*realloc_)(void *ptr, size_t n_bytes, bool allow_move); + int (*printf_)(const mp_print_t *print, const char *fmt, ...); + int (*vprintf_)(const mp_print_t *print, const char *fmt, va_list args); + #if defined(__GNUC__) + NORETURN // Only certain compilers support no-return attributes in function pointer declarations + #endif + void (*raise_msg)(const mp_obj_type_t *exc_type, const char *msg); + mp_obj_type_t *(*obj_get_type)(mp_const_obj_t o_in); + mp_obj_t (*obj_new_str)(const char* data, size_t len); + mp_obj_t (*obj_new_bytes)(const byte* data, size_t len); + mp_obj_t (*obj_new_bytearray_by_ref)(size_t n, void *items); + mp_obj_t (*obj_new_float_from_f)(float f); + mp_obj_t (*obj_new_float_from_d)(double d); + float (*obj_get_float_to_f)(mp_obj_t o); + double (*obj_get_float_to_d)(mp_obj_t o); + void (*get_buffer_raise)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); + const mp_stream_p_t *(*get_stream_raise)(mp_obj_t self_in, int flags); + const mp_print_t *plat_print; + const mp_obj_type_t *type_type; + const mp_obj_type_t *type_str; + const mp_obj_type_t *type_list; + const mp_obj_type_t *type_dict; + const mp_obj_type_t *type_fun_builtin_0; + const mp_obj_type_t *type_fun_builtin_1; + const mp_obj_type_t *type_fun_builtin_2; + const mp_obj_type_t *type_fun_builtin_3; + const mp_obj_type_t *type_fun_builtin_var; + const mp_obj_fun_builtin_var_t *stream_read_obj; + const mp_obj_fun_builtin_var_t *stream_readinto_obj; + const mp_obj_fun_builtin_var_t *stream_unbuffered_readline_obj; + const mp_obj_fun_builtin_var_t *stream_write_obj; +} mp_fun_table_t; + +extern const mp_fun_table_t mp_fun_table; + +#endif // MICROPY_INCLUDED_PY_NATIVEGLUE_H diff --git a/micropython/py/nlr.h b/micropython/py/nlr.h index cbe40e8..f223904 100644 --- a/micropython/py/nlr.h +++ b/micropython/py/nlr.h @@ -35,6 +35,14 @@ #include "py/mpconfig.h" +#define MICROPY_NLR_NUM_REGS_X86 (6) +#define MICROPY_NLR_NUM_REGS_X64 (8) +#define MICROPY_NLR_NUM_REGS_X64_WIN (10) +#define MICROPY_NLR_NUM_REGS_ARM_THUMB (10) +#define MICROPY_NLR_NUM_REGS_ARM_THUMB_FP (10 + 6) +#define MICROPY_NLR_NUM_REGS_XTENSA (10) +#define MICROPY_NLR_NUM_REGS_XTENSAWIN (17) + // If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch #if !MICROPY_NLR_SETJMP // A lot of nlr-related things need different treatment on Windows @@ -45,20 +53,31 @@ #endif #if defined(__i386__) #define MICROPY_NLR_X86 (1) - #define MICROPY_NLR_NUM_REGS (6) + #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X86) #elif defined(__x86_64__) #define MICROPY_NLR_X64 (1) #if MICROPY_NLR_OS_WINDOWS - #define MICROPY_NLR_NUM_REGS (10) + #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X64_WIN) #else - #define MICROPY_NLR_NUM_REGS (8) + #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X64) #endif #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) #define MICROPY_NLR_THUMB (1) - #define MICROPY_NLR_NUM_REGS (10) + #if defined(__SOFTFP__) + #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_ARM_THUMB) + #else + // With hardware FP registers s16-s31 are callee save so in principle + // should be saved and restored by the NLR code. gcc only uses s16-s21 + // so only save/restore those as an optimisation. + #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_ARM_THUMB_FP) + #endif #elif defined(__xtensa__) #define MICROPY_NLR_XTENSA (1) - #define MICROPY_NLR_NUM_REGS (10) + #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_XTENSA) +#elif defined(__powerpc__) + #define MICROPY_NLR_POWERPC (1) + // this could be less but using 128 for safety + #define MICROPY_NLR_NUM_REGS (128) #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" diff --git a/micropython/py/nlrpowerpc.c b/micropython/py/nlrpowerpc.c new file mode 100644 index 0000000..b403823 --- /dev/null +++ b/micropython/py/nlrpowerpc.c @@ -0,0 +1,121 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if MICROPY_NLR_POWERPC + +#undef nlr_push + +// Saving all ABI non-vol registers here + +unsigned int nlr_push(nlr_buf_t *nlr) { + + __asm__ volatile( + "li 4, 0x4eed ; " // Store canary + "std 4, 0x00(%0) ;" + "std 0, 0x08(%0) ;" + "std 1, 0x10(%0) ;" + "std 2, 0x18(%0) ;" + "std 14, 0x20(%0) ;" + "std 15, 0x28(%0) ;" + "std 16, 0x30(%0) ;" + "std 17, 0x38(%0) ;" + "std 18, 0x40(%0) ;" + "std 19, 0x48(%0) ;" + "std 20, 0x50(%0) ;" + "std 21, 0x58(%0) ;" + "std 22, 0x60(%0) ;" + "std 23, 0x68(%0) ;" + "std 24, 0x70(%0) ;" + "std 25, 0x78(%0) ;" + "std 26, 0x80(%0) ;" + "std 27, 0x88(%0) ;" + "std 28, 0x90(%0) ;" + "std 29, 0x98(%0) ;" + "std 30, 0xA0(%0) ;" + "std 31, 0xA8(%0) ;" + + "mfcr 4 ; " + "std 4, 0xB0(%0) ;" + "mflr 4 ;" + "std 4, 0xB8(%0) ;" + "li 4, nlr_push_tail@l ;" + "oris 4, 4, nlr_push_tail@h ;" + "mtctr 4 ;" + "mr 3, %1 ; " + "bctr ;" + : + : "r"(&nlr->regs), "r"(nlr) + : + ); + + return 0; +} + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + + __asm__ volatile( + "ld 3, 0x0(%0) ;" + "cmpdi 3, 0x4eed ; " // Check canary + "bne . ; " + "ld 0, 0x08(%0) ;" + "ld 1, 0x10(%0) ;" + "ld 2, 0x18(%0) ;" + "ld 14, 0x20(%0) ;" + "ld 15, 0x28(%0) ;" + "ld 16, 0x30(%0) ;" + "ld 17, 0x38(%0) ;" + "ld 18, 0x40(%0) ;" + "ld 19, 0x48(%0) ;" + "ld 20, 0x50(%0) ;" + "ld 21, 0x58(%0) ;" + "ld 22, 0x60(%0) ;" + "ld 23, 0x68(%0) ;" + "ld 24, 0x70(%0) ;" + "ld 25, 0x78(%0) ;" + "ld 26, 0x80(%0) ;" + "ld 27, 0x88(%0) ;" + "ld 28, 0x90(%0) ;" + "ld 29, 0x98(%0) ;" + "ld 30, 0xA0(%0) ;" + "ld 31, 0xA8(%0) ;" + "ld 3, 0xB0(%0) ;" + "mtcr 3 ;" + "ld 3, 0xB8(%0) ;" + "mtlr 3 ; " + "li 3, 1;" + "blr ;" + : + : "r"(&top->regs) + : + ); + + MP_UNREACHABLE; +} + +#endif // MICROPY_NLR_POWERPC diff --git a/micropython/py/nlrthumb.c b/micropython/py/nlrthumb.c index 99061e6..bc30388 100644 --- a/micropython/py/nlrthumb.c +++ b/micropython/py/nlrthumb.c @@ -44,7 +44,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { "str r6, [r0, #20] \n" // store r6 into nlr_buf "str r7, [r0, #24] \n" // store r7 into nlr_buf -#if defined(__ARM_ARCH_6M__) +#if !defined(__thumb2__) "mov r1, r8 \n" "str r1, [r0, #28] \n" // store r8 into nlr_buf "mov r1, r9 \n" @@ -63,10 +63,15 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { "str r10, [r0, #36] \n" // store r10 into nlr_buf "str r11, [r0, #40] \n" // store r11 into nlr_buf "str r13, [r0, #44] \n" // store r13=sp into nlr_buf + #if MICROPY_NLR_NUM_REGS == 16 + "vstr d8, [r0, #48] \n" // store s16-s17 into nlr_buf + "vstr d9, [r0, #56] \n" // store s18-s19 into nlr_buf + "vstr d10, [r0, #64] \n" // store s20-s21 into nlr_buf + #endif "str lr, [r0, #8] \n" // store lr into nlr_buf #endif -#if defined(__ARM_ARCH_6M__) +#if !defined(__thumb2__) "ldr r1, nlr_push_tail_var \n" "bx r1 \n" // do the rest in C ".align 2 \n" @@ -97,7 +102,7 @@ NORETURN void nlr_jump(void *val) { "ldr r6, [r0, #20] \n" // load r6 from nlr_buf "ldr r7, [r0, #24] \n" // load r7 from nlr_buf -#if defined(__ARM_ARCH_6M__) +#if !defined(__thumb2__) "ldr r1, [r0, #28] \n" // load r8 from nlr_buf "mov r8, r1 \n" "ldr r1, [r0, #32] \n" // load r9 from nlr_buf @@ -116,6 +121,11 @@ NORETURN void nlr_jump(void *val) { "ldr r10, [r0, #36] \n" // load r10 from nlr_buf "ldr r11, [r0, #40] \n" // load r11 from nlr_buf "ldr r13, [r0, #44] \n" // load r13=sp from nlr_buf + #if MICROPY_NLR_NUM_REGS == 16 + "vldr d8, [r0, #48] \n" // load s16-s17 from nlr_buf + "vldr d9, [r0, #56] \n" // load s18-s19 from nlr_buf + "vldr d10, [r0, #64] \n" // load s20-s21 from nlr_buf + #endif "ldr lr, [r0, #8] \n" // load lr from nlr_buf #endif "movs r0, #1 \n" // return 1, non-local return @@ -125,11 +135,7 @@ NORETURN void nlr_jump(void *val) { : // clobbered registers ); - #if defined(__GNUC__) - __builtin_unreachable(); - #else - for (;;); // needed to silence compiler warning - #endif + MP_UNREACHABLE } #endif // MICROPY_NLR_THUMB diff --git a/micropython/py/nlrx64.c b/micropython/py/nlrx64.c index a3a1cf3..95496b3 100644 --- a/micropython/py/nlrx64.c +++ b/micropython/py/nlrx64.c @@ -108,7 +108,7 @@ NORETURN void nlr_jump(void *val) { : // clobbered registers ); - for (;;); // needed to silence compiler warning + MP_UNREACHABLE } #endif // MICROPY_NLR_X64 diff --git a/micropython/py/nlrx86.c b/micropython/py/nlrx86.c index 59b97d8..6195db6 100644 --- a/micropython/py/nlrx86.c +++ b/micropython/py/nlrx86.c @@ -100,7 +100,7 @@ NORETURN void nlr_jump(void *val) { : // clobbered registers ); - for (;;); // needed to silence compiler warning + MP_UNREACHABLE } #endif // MICROPY_NLR_X86 diff --git a/micropython/py/nlrxtensa.c b/micropython/py/nlrxtensa.c index cd3dee3..895b202 100644 --- a/micropython/py/nlrxtensa.c +++ b/micropython/py/nlrxtensa.c @@ -77,7 +77,7 @@ NORETURN void nlr_jump(void *val) { : // clobbered registers ); - for (;;); // needed to silence compiler warning + MP_UNREACHABLE } #endif // MICROPY_NLR_XTENSA diff --git a/micropython/py/obj.c b/micropython/py/obj.c index 122f0ea..4588d89 100644 --- a/micropython/py/obj.c +++ b/micropython/py/obj.c @@ -93,7 +93,7 @@ void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) { #endif // the block name can be NULL if it's unknown qstr block = values[i + 2]; - if (block == MP_QSTR_NULL) { + if (block == MP_QSTRnull) { mp_print_str(print, "\n"); } else { mp_printf(print, ", in %q\n", block); @@ -113,7 +113,7 @@ bool mp_obj_is_true(mp_obj_t arg) { } else if (arg == mp_const_none) { return 0; } else if (mp_obj_is_small_int(arg)) { - if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) { + if (arg == MP_OBJ_NEW_SMALL_INT(0)) { return 0; } else { return 1; diff --git a/micropython/py/obj.h b/micropython/py/obj.h index d48990b..b832ab9 100644 --- a/micropython/py/obj.h +++ b/micropython/py/obj.h @@ -205,7 +205,6 @@ static inline bool mp_obj_is_qstr(mp_const_obj_t o) static inline bool mp_obj_is_obj(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); } - #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D static inline bool mp_obj_is_small_int(mp_const_obj_t o) @@ -744,7 +743,6 @@ mp_float_t mp_obj_get_float(mp_obj_t self_in); bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); #endif -//qstr mp_obj_get_qstr(mp_obj_t arg); void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items); // *items may point inside a GC block void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items); // *items may point inside a GC block size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice); diff --git a/micropython/py/objarray.c b/micropython/py/objarray.c index 4e58d8e..c19617d 100644 --- a/micropython/py/objarray.c +++ b/micropython/py/objarray.c @@ -445,7 +445,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value if (len_adj > o->free) { // TODO: alloc policy; at the moment we go conservative o->items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz); - o->free = 0; + o->free = len_adj; dest_items = o->items; } mp_seq_replace_slice_grow_inplace(dest_items, o->len, @@ -458,6 +458,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_seq_clear(dest_items, o->len + len_adj, o->len, item_sz); // TODO: alloc policy after shrinking } + o->free -= len_adj; o->len += len_adj; return mp_const_none; #else diff --git a/micropython/py/objdict.c b/micropython/py/objdict.c index 0a223f7..7a43a85 100644 --- a/micropython/py/objdict.c +++ b/micropython/py/objdict.c @@ -31,6 +31,7 @@ #include "py/runtime.h" #include "py/builtin.h" #include "py/objtype.h" +#include "py/objstr.h" #define mp_obj_is_dict_type(o) (mp_obj_is_obj(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new) @@ -59,7 +60,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { kind = PRINT_REPR; } - if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict) { + if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) { mp_printf(print, "%q(", self->base.type->name); } mp_print_str(print, "{"); @@ -70,12 +71,19 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ mp_print_str(print, ", "); } first = false; + bool add_quote = MICROPY_PY_UJSON && kind == PRINT_JSON && !mp_obj_is_str_or_bytes(next->key); + if (add_quote) { + mp_print_str(print, "\""); + } mp_obj_print_helper(print, next->key, kind); + if (add_quote) { + mp_print_str(print, "\""); + } mp_print_str(print, ": "); mp_obj_print_helper(print, next->value, kind); } mp_print_str(print, "}"); - if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict) { + if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) { mp_print_str(print, ")"); } } diff --git a/micropython/py/objenumerate.c b/micropython/py/objenumerate.c index 493e45c..243c9f8 100644 --- a/micropython/py/objenumerate.c +++ b/micropython/py/objenumerate.c @@ -59,7 +59,7 @@ STATIC mp_obj_t enumerate_make_new(const mp_obj_type_t *type, size_t n_args, siz o->iter = mp_getiter(arg_vals.iterable.u_obj, NULL); o->cur = arg_vals.start.u_int; #else - (void)n_kw; + mp_arg_check_num(n_args, n_kw, 1, 2, false); mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t); o->base.type = type; o->iter = mp_getiter(args[0], NULL); diff --git a/micropython/py/objexcept.c b/micropython/py/objexcept.c index 1fb636f..dadbe98 100644 --- a/micropython/py/objexcept.c +++ b/micropython/py/objexcept.c @@ -100,11 +100,6 @@ mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) { #endif #endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF -// Instance of GeneratorExit exception - needed by generator.close() -// This would belong to objgenerator.c, but to keep mp_obj_exception_t -// definition module-private so far, have it here. -const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; - void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_exception_t *o = MP_OBJ_TO_PTR(o_in); mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; @@ -126,7 +121,7 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin // try to provide a nice OSError error message if (o->base.type == &mp_type_OSError && mp_obj_is_small_int(o->args->items[0])) { qstr qst = mp_errno_to_str(o->args->items[0]); - if (qst != MP_QSTR_NULL) { + if (qst != MP_QSTRnull) { mp_printf(print, "[Errno " INT_FMT "] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst); return; } diff --git a/micropython/py/objfun.c b/micropython/py/objfun.c index 7f320fe..8edacef 100644 --- a/micropython/py/objfun.c +++ b/micropython/py/objfun.c @@ -140,7 +140,7 @@ const mp_obj_type_t mp_type_fun_builtin_var = { /* byte code functions */ qstr mp_obj_code_get_name(const byte *code_info) { - code_info = mp_decode_uint_skip(code_info); // skip code_info_size entry + MP_BC_PRELUDE_SIZE_DECODE(code_info); #if MICROPY_PERSISTENT_CODE return code_info[0] | (code_info[1] << 8); #else @@ -162,12 +162,7 @@ qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) { #endif const byte *bc = fun->bytecode; - bc = mp_decode_uint_skip(bc); // skip n_state - bc = mp_decode_uint_skip(bc); // skip n_exc_stack - bc++; // skip scope_params - bc++; // skip n_pos_args - bc++; // skip n_kwonly_args - bc++; // skip n_def_pos_args + MP_BC_PRELUDE_SIG_DECODE(bc); return mp_obj_code_get_name(bc); } @@ -198,18 +193,19 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { #define DECODE_CODESTATE_SIZE(bytecode, n_state_out_var, state_size_out_var) \ { \ - /* bytecode prelude: state size and exception stack size */ \ - n_state_out_var = mp_decode_uint_value(bytecode); \ - size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(bytecode)); \ - \ + const uint8_t *ip = bytecode; \ + size_t n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_args; \ + MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state_out_var, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_args); \ + \ /* state size in bytes */ \ state_size_out_var = n_state_out_var * sizeof(mp_obj_t) \ + n_exc_stack * sizeof(mp_exc_stack_t); \ } -#define INIT_CODESTATE(code_state, _fun_bc, n_args, n_kw, args) \ +#define INIT_CODESTATE(code_state, _fun_bc, _n_state, n_args, n_kw, args) \ code_state->fun_bc = _fun_bc; \ code_state->ip = 0; \ + code_state->n_state = _n_state; \ mp_setup_code_state(code_state, n_args, n_kw, args); \ code_state->old_globals = mp_globals_get(); @@ -236,7 +232,7 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args } } - INIT_CODESTATE(code_state, self, n_args, n_kw, args); + INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args); // execute the byte code with the correct globals context mp_globals_set(self->globals); @@ -282,7 +278,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const } } - INIT_CODESTATE(code_state, self, n_args, n_kw, args); + INIT_CODESTATE(code_state, self, n_state, n_args, n_kw, args); // execute the byte code with the correct globals context mp_globals_set(self->globals); @@ -296,9 +292,11 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const assert(0); } } - const byte *bytecode_ptr = mp_decode_uint_skip(mp_decode_uint_skip(self->bytecode)); - size_t n_pos_args = bytecode_ptr[1]; - size_t n_kwonly_args = bytecode_ptr[2]; + const byte *bytecode_ptr = self->bytecode; + size_t n_state_unused, n_exc_stack_unused, scope_flags_unused; + size_t n_pos_args, n_kwonly_args, n_def_args_unused; + MP_BC_PRELUDE_SIG_DECODE_INTO(bytecode_ptr, n_state_unused, n_exc_stack_unused, + scope_flags_unused, n_pos_args, n_kwonly_args, n_def_args_unused); // We can't check the case when an exception is returned in state[0] // and there are no arguments, because in this case our detection slot may have // been overwritten by the returned exception (which is allowed). @@ -473,7 +471,7 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { return (mp_uint_t)items; } else { mp_buffer_info_t bufinfo; - if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_WRITE)) { + if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_READ)) { // supports the buffer protocol, return a pointer to the data return (mp_uint_t)bufinfo.buf; } else { diff --git a/micropython/py/objfun.h b/micropython/py/objfun.h index 257b8a6..905b5db 100644 --- a/micropython/py/objfun.h +++ b/micropython/py/objfun.h @@ -33,6 +33,9 @@ typedef struct _mp_obj_fun_bc_t { mp_obj_dict_t *globals; // the context within which this function was defined const byte *bytecode; // bytecode for the function const mp_uint_t *const_table; // constant table + #if MICROPY_PY_SYS_SETTRACE + const struct _mp_raw_code_t *rc; + #endif // the following extra_args array is allocated space to take (in order): // - values of positional default args (if any) // - a single slot for default kw args dict (if it has them) diff --git a/micropython/py/objgenerator.c b/micropython/py/objgenerator.c index 29c7cb1..903a646 100644 --- a/micropython/py/objgenerator.c +++ b/micropython/py/objgenerator.c @@ -30,16 +30,23 @@ #include "py/runtime.h" #include "py/bc.h" +#include "py/objstr.h" #include "py/objgenerator.h" #include "py/objfun.h" #include "py/stackctrl.h" +// Instance of GeneratorExit exception - needed by generator.close() +const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; + /******************************************************************************/ /* generator wrapper */ typedef struct _mp_obj_gen_instance_t { mp_obj_base_t base; - mp_obj_dict_t *globals; + // mp_const_none: Not-running, no exception. + // MP_OBJ_NULL: Running, no exception. + // other: Not running, pending exception. + mp_obj_t pend_exc; mp_code_state_t code_state; } mp_obj_gen_instance_t; @@ -48,17 +55,18 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in); // bytecode prelude: get state size and exception stack size - size_t n_state = mp_decode_uint_value(self_fun->bytecode); - size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self_fun->bytecode)); + const uint8_t *ip = self_fun->bytecode; + MP_BC_PRELUDE_SIG_DECODE(ip); // allocate the generator object, with room for local stack and exception stack mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); o->base.type = &mp_type_gen_instance; - o->globals = self_fun->globals; + o->pend_exc = mp_const_none; o->code_state.fun_bc = self_fun; o->code_state.ip = 0; + o->code_state.n_state = n_state; mp_setup_code_state(&o->code_state, n_args, n_kw, args); return MP_OBJ_FROM_PTR(o); } @@ -84,7 +92,14 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k // Determine start of prelude, and extract n_state from it uintptr_t prelude_offset = ((uintptr_t*)self_fun->bytecode)[0]; - size_t n_state = mp_decode_uint_value(self_fun->bytecode + prelude_offset); + #if MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ + // Prelude is in bytes object in const_table, at index prelude_offset + mp_obj_str_t *prelude_bytes = MP_OBJ_TO_PTR(self_fun->const_table[prelude_offset]); + prelude_offset = (const byte*)prelude_bytes->data - self_fun->bytecode; + #endif + const uint8_t *ip = self_fun->bytecode + prelude_offset; + size_t n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args; + MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args); size_t n_exc_stack = 0; // Allocate the generator object, with room for local stack and exception stack @@ -93,13 +108,14 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k o->base.type = &mp_type_gen_instance; // Parse the input arguments and set up the code state - o->globals = self_fun->globals; + o->pend_exc = mp_const_none; o->code_state.fun_bc = self_fun; o->code_state.ip = (const byte*)prelude_offset; + o->code_state.n_state = n_state; mp_setup_code_state(&o->code_state, n_args, n_kw, args); // Indicate we are a native function, which doesn't use this variable - o->code_state.exc_sp = NULL; + o->code_state.exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_SENTINEL; // Prepare the generator instance for execution uintptr_t start_offset = ((uintptr_t*)self_fun->bytecode)[1]; @@ -138,38 +154,39 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ *ret_val = MP_OBJ_STOP_ITERATION; return MP_VM_RETURN_NORMAL; } + + // Ensure the generator cannot be reentered during execution + if (self->pend_exc == MP_OBJ_NULL) { + mp_raise_ValueError("generator already executing"); + } + + #if MICROPY_PY_GENERATOR_PEND_THROW + // If exception is pending (set using .pend_throw()), process it now. + if (self->pend_exc != mp_const_none) { + throw_value = self->pend_exc; + } + #endif + + // If the generator is started, allow sending a value. if (self->code_state.sp == self->code_state.state - 1) { if (send_value != mp_const_none) { mp_raise_TypeError("can't send non-None value to a just-started generator"); } } else { - #if MICROPY_PY_GENERATOR_PEND_THROW - // If exception is pending (set using .pend_throw()), process it now. - if (*self->code_state.sp != mp_const_none) { - throw_value = *self->code_state.sp; - *self->code_state.sp = MP_OBJ_NULL; - } else - #endif - { - *self->code_state.sp = send_value; - } + *self->code_state.sp = send_value; } - // We set self->globals=NULL while executing, for a sentinel to ensure the generator - // cannot be reentered during execution - if (self->globals == NULL) { - mp_raise_ValueError("generator already executing"); - } + // Mark as running + self->pend_exc = MP_OBJ_NULL; // Set up the correct globals context for the generator and execute it self->code_state.old_globals = mp_globals_get(); - mp_globals_set(self->globals); - self->globals = NULL; + mp_globals_set(self->code_state.fun_bc->globals); mp_vm_return_kind_t ret_kind; #if MICROPY_EMIT_NATIVE - if (self->code_state.exc_sp == NULL) { + if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) { // A native generator, with entry point 2 words into the "bytecode" pointer typedef uintptr_t (*mp_fun_native_gen_t)(void*, mp_obj_t); mp_fun_native_gen_t fun = MICROPY_MAKE_POINTER_CALLABLE((const void*)(self->code_state.fun_bc->bytecode + 2 * sizeof(uintptr_t))); @@ -181,9 +198,11 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ ret_kind = mp_execute_bytecode(&self->code_state, throw_value); } - self->globals = mp_globals_get(); mp_globals_set(self->code_state.old_globals); + // Mark as not running + self->pend_exc = mp_const_none; + switch (ret_kind) { case MP_VM_RETURN_NORMAL: default: @@ -297,16 +316,18 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close); +#if MICROPY_PY_GENERATOR_PEND_THROW STATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) { mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); - if (self->code_state.sp == self->code_state.state - 1) { - mp_raise_TypeError("can't pend throw to just-started generator"); + if (self->pend_exc == MP_OBJ_NULL) { + mp_raise_ValueError("generator already executing"); } - mp_obj_t prev = *self->code_state.sp; - *self->code_state.sp = exc_in; + mp_obj_t prev = self->pend_exc; + self->pend_exc = exc_in; return prev; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_pend_throw_obj, gen_instance_pend_throw); +#endif STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&gen_instance_close_obj) }, diff --git a/micropython/py/objint.c b/micropython/py/objint.c index 6473767..2fdcf58 100644 --- a/micropython/py/objint.c +++ b/micropython/py/objint.c @@ -137,7 +137,7 @@ STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { int cl = fpclassify(val); if (cl == FP_INFINITE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "can't convert inf to int")); + mp_raise_msg(&mp_type_OverflowError, "can't convert inf to int"); } else if (cl == FP_NAN) { mp_raise_ValueError("can't convert NaN to int"); } else { diff --git a/micropython/py/objmodule.c b/micropython/py/objmodule.c index 4a07913..81558a0 100644 --- a/micropython/py/objmodule.c +++ b/micropython/py/objmodule.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 Damien P. George * Copyright (c) 2014-2015 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,6 +26,7 @@ */ #include +#include #include #include "py/objmodule.h" @@ -223,6 +224,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { #if MICROPY_PY_BTREE { MP_ROM_QSTR(MP_QSTR_btree), MP_ROM_PTR(&mp_module_btree) }, #endif +#if MICROPY_PY_BLUETOOTH + { MP_ROM_QSTR(MP_QSTR_ubluetooth), MP_ROM_PTR(&mp_module_ubluetooth) }, +#endif // extra builtin modules as defined by a port MICROPY_PORT_BUILTIN_MODULES @@ -235,14 +239,6 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table); -#if MICROPY_MODULE_WEAK_LINKS -STATIC const mp_rom_map_elem_t mp_builtin_module_weak_links_table[] = { - MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS -}; - -MP_DEFINE_CONST_MAP(mp_builtin_module_weak_links_map, mp_builtin_module_weak_links_table); -#endif - // returns MP_OBJ_NULL if not found mp_obj_t mp_module_get(qstr module_name) { mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; @@ -267,6 +263,21 @@ void mp_module_register(qstr qst, mp_obj_t module) { mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; } +#if MICROPY_MODULE_WEAK_LINKS +// Search for u"foo" in built-in modules, return MP_OBJ_NULL if not found +mp_obj_t mp_module_search_umodule(const char *module_str) { + for (size_t i = 0; i < MP_ARRAY_SIZE(mp_builtin_module_table); ++i) { + const mp_map_elem_t *entry = (const mp_map_elem_t*)&mp_builtin_module_table[i]; + const char *key = qstr_str(MP_OBJ_QSTR_VALUE(entry->key)); + if (key[0] == 'u' && strcmp(&key[1], module_str) == 0) { + return (mp_obj_t)entry->value; + } + + } + return MP_OBJ_NULL; +} +#endif + #if MICROPY_MODULE_BUILTIN_INIT void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { // Look for __init__ and call it if it exists diff --git a/micropython/py/objmodule.h b/micropython/py/objmodule.h index b7702ec..33a0ff0 100644 --- a/micropython/py/objmodule.h +++ b/micropython/py/objmodule.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2019 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +34,8 @@ extern const mp_map_t mp_builtin_module_weak_links_map; mp_obj_t mp_module_get(qstr module_name); void mp_module_register(qstr qstr, mp_obj_t module); +mp_obj_t mp_module_search_umodule(const char *module_str); + #if MICROPY_MODULE_BUILTIN_INIT void mp_module_call_init(qstr module_name, mp_obj_t module_obj); #else diff --git a/micropython/py/objstr.c b/micropython/py/objstr.c index 1047ea9..e221982 100644 --- a/micropython/py/objstr.c +++ b/micropython/py/objstr.c @@ -169,7 +169,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ // Check if a qstr with this data already exists qstr q = qstr_find_strn((const char*)str_data, str_len); - if (q != MP_QSTR_NULL) { + if (q != MP_QSTRnull) { return MP_OBJ_NEW_QSTR(q); } @@ -1913,9 +1913,6 @@ mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_u return 0; } else { // can't write to a string - bufinfo->buf = NULL; - bufinfo->len = 0; - bufinfo->typecode = -1; return 1; } } @@ -2042,7 +2039,7 @@ mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) { // if not a bytes object, look if a qstr with this data already exists if (type == &mp_type_str) { qstr q = qstr_find_strn(vstr->buf, vstr->len); - if (q != MP_QSTR_NULL) { + if (q != MP_QSTRnull) { vstr_clear(vstr); vstr->alloc = 0; return MP_OBJ_NEW_QSTR(q); @@ -2067,7 +2064,7 @@ mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) { mp_obj_t mp_obj_new_str(const char* data, size_t len) { qstr q = qstr_find_strn(data, len); - if (q != MP_QSTR_NULL) { + if (q != MP_QSTRnull) { // qstr with this data already exists return MP_OBJ_NEW_QSTR(q); } else { diff --git a/micropython/py/objstringio.c b/micropython/py/objstringio.c index 89b6790..cca4a81 100644 --- a/micropython/py/objstringio.c +++ b/micropython/py/objstringio.c @@ -70,9 +70,9 @@ STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *er STATIC void stringio_copy_on_write(mp_obj_stringio_t *o) { const void *buf = o->vstr->buf; o->vstr->buf = m_new(char, o->vstr->len); - memcpy(o->vstr->buf, buf, o->vstr->len); o->vstr->fixed_buf = false; o->ref_obj = MP_OBJ_NULL; + memcpy(o->vstr->buf, buf, o->vstr->len); } STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { @@ -244,12 +244,6 @@ STATIC const mp_stream_p_t stringio_stream_p = { .is_text = true, }; -STATIC const mp_stream_p_t bytesio_stream_p = { - .read = stringio_read, - .write = stringio_write, - .ioctl = stringio_ioctl, -}; - const mp_obj_type_t mp_type_stringio = { { &mp_type_type }, .name = MP_QSTR_StringIO, @@ -262,6 +256,12 @@ const mp_obj_type_t mp_type_stringio = { }; #if MICROPY_PY_IO_BYTESIO +STATIC const mp_stream_p_t bytesio_stream_p = { + .read = stringio_read, + .write = stringio_write, + .ioctl = stringio_ioctl, +}; + const mp_obj_type_t mp_type_bytesio = { { &mp_type_type }, .name = MP_QSTR_BytesIO, diff --git a/micropython/py/objtuple.c b/micropython/py/objtuple.c index 39eb940..740e079 100644 --- a/micropython/py/objtuple.c +++ b/micropython/py/objtuple.c @@ -31,6 +31,9 @@ #include "py/objtuple.h" #include "py/runtime.h" +// type check is done on getiter method to allow tuple, namedtuple, attrtuple +#define mp_obj_is_tuple_compatible(o) (mp_obj_get_type(o)->getiter == mp_obj_tuple_getiter) + /******************************************************************************/ /* tuple */ @@ -101,8 +104,7 @@ STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_arg // Don't pass MP_BINARY_OP_NOT_EQUAL here STATIC mp_obj_t tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) { - // type check is done on getiter method to allow tuple, namedtuple, attrtuple - mp_check_self(mp_obj_get_type(self_in)->getiter == mp_obj_tuple_getiter); + mp_check_self(mp_obj_is_tuple_compatible(self_in)); mp_obj_type_t *another_type = mp_obj_get_type(another_in); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); if (another_type->getiter != mp_obj_tuple_getiter) { @@ -249,7 +251,7 @@ mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { } void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { - assert(mp_obj_is_type(self_in, &mp_type_tuple)); + assert(mp_obj_is_tuple_compatible(self_in)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); *len = self->len; *items = &self->items[0]; diff --git a/micropython/py/objtype.c b/micropython/py/objtype.c index 3e65a32..bf089dc 100644 --- a/micropython/py/objtype.c +++ b/micropython/py/objtype.c @@ -460,7 +460,7 @@ STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } // Binary-op enum values not listed here will have the default value of 0 in the -// table, corresponding to MP_QSTR_NULL, and are therefore unsupported (a lookup will +// table, corresponding to MP_QSTRnull, and are therefore unsupported (a lookup will // fail). They can be added at the expense of code size for the qstr. // Qstrs for special methods are guaranteed to have a small value, so we use byte // type to represent them. @@ -478,6 +478,7 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = { [MP_BINARY_OP_INPLACE_SUBTRACT] = MP_QSTR___isub__, #if MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS [MP_BINARY_OP_INPLACE_MULTIPLY] = MP_QSTR___imul__, + [MP_BINARY_OP_INPLACE_MAT_MULTIPLY] = MP_QSTR___imatmul__, [MP_BINARY_OP_INPLACE_FLOOR_DIVIDE] = MP_QSTR___ifloordiv__, [MP_BINARY_OP_INPLACE_TRUE_DIVIDE] = MP_QSTR___itruediv__, [MP_BINARY_OP_INPLACE_MODULO] = MP_QSTR___imod__, @@ -493,6 +494,7 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = { [MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__, #if MICROPY_PY_ALL_SPECIAL_METHODS [MP_BINARY_OP_MULTIPLY] = MP_QSTR___mul__, + [MP_BINARY_OP_MAT_MULTIPLY] = MP_QSTR___matmul__, [MP_BINARY_OP_FLOOR_DIVIDE] = MP_QSTR___floordiv__, [MP_BINARY_OP_TRUE_DIVIDE] = MP_QSTR___truediv__, [MP_BINARY_OP_MODULO] = MP_QSTR___mod__, @@ -510,6 +512,7 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = { [MP_BINARY_OP_REVERSE_SUBTRACT] = MP_QSTR___rsub__, #if MICROPY_PY_ALL_SPECIAL_METHODS [MP_BINARY_OP_REVERSE_MULTIPLY] = MP_QSTR___rmul__, + [MP_BINARY_OP_REVERSE_MAT_MULTIPLY] = MP_QSTR___rmatmul__, [MP_BINARY_OP_REVERSE_FLOOR_DIVIDE] = MP_QSTR___rfloordiv__, [MP_BINARY_OP_REVERSE_TRUE_DIVIDE] = MP_QSTR___rtruediv__, [MP_BINARY_OP_REVERSE_MODULO] = MP_QSTR___rmod__, @@ -1011,6 +1014,21 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[0] = MP_OBJ_NEW_QSTR(self->name); return; } + if (attr == MP_QSTR___bases__) { + if (self == &mp_type_object) { + dest[0] = mp_const_empty_tuple; + return; + } + mp_obj_t parent_obj = self->parent ? MP_OBJ_FROM_PTR(self->parent) : MP_OBJ_FROM_PTR(&mp_type_object); + #if MICROPY_MULTIPLE_INHERITANCE + if (mp_obj_is_type(parent_obj, &mp_type_tuple)) { + dest[0] = parent_obj; + return; + } + #endif + dest[0] = mp_obj_new_tuple(1, &parent_obj); + return; + } #endif struct class_lookup_data lookup = { .obj = (mp_obj_instance_t*)self, diff --git a/micropython/py/parse.c b/micropython/py/parse.c index 66110e7..82b5413 100644 --- a/micropython/py/parse.c +++ b/micropython/py/parse.c @@ -135,8 +135,8 @@ STATIC const uint16_t rule_arg_combined_table[] = { #define RULE_EXPAND(x) x #define RULE_PADDING(rule, ...) RULE_PADDING2(rule, __VA_ARGS__, RULE_PADDING_IDS(rule)) #define RULE_PADDING2(rule, ...) RULE_EXPAND(RULE_PADDING3(rule, __VA_ARGS__)) -#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) __VA_ARGS__ -#define RULE_PADDING_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, +#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) __VA_ARGS__ +#define RULE_PADDING_IDS(r) PAD13_##r, PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, // Use an enum to create constants specifying how much room a rule takes in rule_arg_combined_table enum { @@ -155,8 +155,8 @@ enum { // Macro to compute the start of a rule in rule_arg_combined_table #define RULE_ARG_OFFSET(rule, ...) RULE_ARG_OFFSET2(rule, __VA_ARGS__, RULE_ARG_OFFSET_IDS(rule)) #define RULE_ARG_OFFSET2(rule, ...) RULE_EXPAND(RULE_ARG_OFFSET3(rule, __VA_ARGS__)) -#define RULE_ARG_OFFSET3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) _13 -#define RULE_ARG_OFFSET_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, PAD0_##r, +#define RULE_ARG_OFFSET3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) _14 +#define RULE_ARG_OFFSET_IDS(r) PAD13_##r, PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, PAD0_##r, // Use the above enum values to create a table of offsets for each rule's arg // data, which indexes rule_arg_combined_table. The offsets require 9 bits of @@ -502,7 +502,7 @@ STATIC void push_result_token(parser_t *parser, uint8_t rule_id) { } else if (lex->tok_kind == MP_TOKEN_STRING || lex->tok_kind == MP_TOKEN_BYTES) { // Don't automatically intern all strings/bytes. doc strings (which are usually large) // will be discarded by the compiler, and so we shouldn't intern them. - qstr qst = MP_QSTR_NULL; + qstr qst = MP_QSTRnull; if (lex->vstr.len <= MICROPY_ALLOC_PARSE_INTERN_STRING_LEN) { // intern short strings qst = qstr_from_strn(lex->vstr.buf, lex->vstr.len); @@ -510,7 +510,7 @@ STATIC void push_result_token(parser_t *parser, uint8_t rule_id) { // check if this string is already interned qst = qstr_find_strn(lex->vstr.buf, lex->vstr.len); } - if (qst != MP_QSTR_NULL) { + if (qst != MP_QSTRnull) { // qstr exists, make a leaf node pn = mp_parse_node_new_leaf(lex->tok_kind == MP_TOKEN_STRING ? MP_PARSE_NODE_STRING : MP_PARSE_NODE_BYTES, qst); } else { @@ -632,7 +632,7 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { } else if (rule_id == RULE_shift_expr || rule_id == RULE_arith_expr || rule_id == RULE_term) { - // folding for binary ops: << >> + - * / % // + // folding for binary ops: << >> + - * @ / % // mp_parse_node_t pn = peek_result(parser, num_args - 1); if (!mp_parse_node_get_int_maybe(pn, &arg0)) { return false; @@ -644,23 +644,11 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { return false; } mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, i)); - static const uint8_t token_to_op[] = { - MP_BINARY_OP_ADD, - MP_BINARY_OP_SUBTRACT, - MP_BINARY_OP_MULTIPLY, - 255,//MP_BINARY_OP_POWER, - 255,//MP_BINARY_OP_TRUE_DIVIDE, - MP_BINARY_OP_FLOOR_DIVIDE, - MP_BINARY_OP_MODULO, - 255,//MP_BINARY_OP_LESS - MP_BINARY_OP_LSHIFT, - 255,//MP_BINARY_OP_MORE - MP_BINARY_OP_RSHIFT, - }; - mp_binary_op_t op = token_to_op[tok - MP_TOKEN_OP_PLUS]; - if (op == (mp_binary_op_t)255) { + if (tok == MP_TOKEN_OP_AT || tok == MP_TOKEN_OP_SLASH || tok == MP_TOKEN_OP_DBL_STAR) { + // Can't fold @ or / or ** return false; } + mp_binary_op_t op = MP_BINARY_OP_LSHIFT + (tok - MP_TOKEN_OP_DBL_LESS); int rhs_sign = mp_obj_int_sign(arg1); if (op <= MP_BINARY_OP_RSHIFT) { // << and >> can't have negative rhs @@ -683,13 +671,11 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { } mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, 1)); mp_unary_op_t op; - if (tok == MP_TOKEN_OP_PLUS) { - op = MP_UNARY_OP_POSITIVE; - } else if (tok == MP_TOKEN_OP_MINUS) { - op = MP_UNARY_OP_NEGATIVE; - } else { - assert(tok == MP_TOKEN_OP_TILDE); // should be + if (tok == MP_TOKEN_OP_TILDE) { op = MP_UNARY_OP_INVERT; + } else { + assert(tok == MP_TOKEN_OP_PLUS || tok == MP_TOKEN_OP_MINUS); // should be + op = MP_UNARY_OP_POSITIVE + (tok - MP_TOKEN_OP_PLUS); } arg0 = mp_unary_op(op, arg0); @@ -719,7 +705,7 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, "constant must be an integer"); mp_obj_exception_add_traceback(exc, parser->lexer->source_name, - ((mp_parse_node_struct_t*)pn1)->source_line, MP_QSTR_NULL); + ((mp_parse_node_struct_t*)pn1)->source_line, MP_QSTRnull); nlr_raise(exc); } @@ -1152,7 +1138,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } // add traceback to give info about file name and location // we don't have a 'block' name, so just pass the NULL qstr to indicate this - mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTR_NULL); + mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTRnull); nlr_raise(exc); } diff --git a/micropython/py/parsenum.c b/micropython/py/parsenum.c index ae9b834..2b01b72 100644 --- a/micropython/py/parsenum.c +++ b/micropython/py/parsenum.c @@ -41,7 +41,7 @@ STATIC NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) { // exception's type from ValueError to SyntaxError and add traceback info if (lex != NULL) { ((mp_obj_base_t*)MP_OBJ_TO_PTR(exc))->type = &mp_type_SyntaxError; - mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTR_NULL); + mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTRnull); } nlr_raise(exc); } diff --git a/micropython/py/persistentcode.c b/micropython/py/persistentcode.c index ed017f0..f5b7d97 100644 --- a/micropython/py/persistentcode.c +++ b/micropython/py/persistentcode.c @@ -31,9 +31,10 @@ #include #include "py/reader.h" -#include "py/emitglue.h" +#include "py/nativeglue.h" #include "py/persistentcode.h" -#include "py/bc.h" +#include "py/bc0.h" +#include "py/objstr.h" #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE @@ -41,41 +42,6 @@ #define QSTR_LAST_STATIC MP_QSTR_zip -// Macros to encode/decode flags to/from the feature byte -#define MPY_FEATURE_ENCODE_FLAGS(flags) (flags) -#define MPY_FEATURE_DECODE_FLAGS(feat) ((feat) & 3) - -// Macros to encode/decode native architecture to/from the feature byte -#define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2) -#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2) - -// The feature flag bits encode the compile-time config options that -// affect the generate bytecode. -#define MPY_FEATURE_FLAGS ( \ - ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \ - | ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \ - ) -// This is a version of the flags that can be configured at runtime. -#define MPY_FEATURE_FLAGS_DYNAMIC ( \ - ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) << 0) \ - | ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \ - ) - -// Define the host architecture -#if MICROPY_EMIT_X86 -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) -#elif MICROPY_EMIT_X64 -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) -#elif MICROPY_EMIT_THUMB -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7M) -#elif MICROPY_EMIT_ARM -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) -#elif MICROPY_EMIT_XTENSA -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) -#else -#define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) -#endif - #if MICROPY_DYNAMIC_COMPILER #define MPY_FEATURE_ARCH_DYNAMIC mp_dynamic_compiler.native_arch #else @@ -158,33 +124,38 @@ typedef struct _bytecode_prelude_t { uint code_info_size; } bytecode_prelude_t; -#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_EMIT_NATIVE - // ip will point to start of opcodes -// ip2 will point to simple_name, source_file qstrs -STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_t *prelude) { - prelude->n_state = mp_decode_uint(ip); - prelude->n_exc_stack = mp_decode_uint(ip); - prelude->scope_flags = *(*ip)++; - prelude->n_pos_args = *(*ip)++; - prelude->n_kwonly_args = *(*ip)++; - prelude->n_def_pos_args = *(*ip)++; - *ip2 = *ip; - prelude->code_info_size = mp_decode_uint(ip2); - *ip += prelude->code_info_size; - while (*(*ip)++ != 255) { - } +// return value will point to simple_name, source_file qstrs +STATIC byte *extract_prelude(const byte **ip, bytecode_prelude_t *prelude) { + MP_BC_PRELUDE_SIG_DECODE(*ip); + prelude->n_state = n_state; + prelude->n_exc_stack = n_exc_stack; + prelude->scope_flags = scope_flags; + prelude->n_pos_args = n_pos_args; + prelude->n_kwonly_args = n_kwonly_args; + prelude->n_def_pos_args = n_def_pos_args; + MP_BC_PRELUDE_SIZE_DECODE(*ip); + byte *ip_info = (byte*)*ip; + *ip += n_info; + *ip += n_cell; + return ip_info; } -#endif - #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE #if MICROPY_PERSISTENT_CODE_LOAD #include "py/parsenum.h" -#if MICROPY_EMIT_NATIVE +STATIC int read_byte(mp_reader_t *reader); +STATIC size_t read_uint(mp_reader_t *reader, byte **out); + +#if MICROPY_EMIT_MACHINE_CODE + +typedef struct _reloc_info_t { + mp_reader_t *reader; + mp_uint_t *const_table; +} reloc_info_t; #if MICROPY_EMIT_THUMB STATIC void asm_thumb_rewrite_mov(uint8_t *pc, uint16_t val) { @@ -201,7 +172,7 @@ STATIC void arch_link_qstr(uint8_t *pc, bool is_obj, qstr qst) { if (is_obj) { val = (mp_uint_t)MP_OBJ_NEW_QSTR(qst); } - #if MICROPY_EMIT_X86 || MICROPY_EMIT_X64 || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA + #if MICROPY_EMIT_X86 || MICROPY_EMIT_X64 || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA || MICROPY_EMIT_XTENSAWIN pc[0] = val & 0xff; pc[1] = (val >> 8) & 0xff; pc[2] = (val >> 16) & 0xff; @@ -218,6 +189,52 @@ STATIC void arch_link_qstr(uint8_t *pc, bool is_obj, qstr qst) { #endif } +void mp_native_relocate(void *ri_in, uint8_t *text, uintptr_t reloc_text) { + // Relocate native code + reloc_info_t *ri = ri_in; + uint8_t op; + uintptr_t *addr_to_adjust = NULL; + while ((op = read_byte(ri->reader)) != 0xff) { + if (op & 1) { + // Point to new location to make adjustments + size_t addr = read_uint(ri->reader, NULL); + if ((addr & 1) == 0) { + // Point to somewhere in text + addr_to_adjust = &((uintptr_t*)text)[addr >> 1]; + } else { + // Point to somewhere in rodata + addr_to_adjust = &((uintptr_t*)ri->const_table[1])[addr >> 1]; + } + } + op >>= 1; + uintptr_t dest; + size_t n = 1; + if (op <= 5) { + if (op & 1) { + // Read in number of adjustments to make + n = read_uint(ri->reader, NULL); + } + op >>= 1; + if (op == 0) { + // Destination is text + dest = reloc_text; + } else { + // Destination is rodata (op=1) or bss (op=1 if no rodata, else op=2) + dest = ri->const_table[op]; + } + } else if (op == 6) { + // Destination is mp_fun_table itself + dest = (uintptr_t)&mp_fun_table; + } else { + // Destination is an entry in mp_fun_table + dest = ((uintptr_t*)&mp_fun_table)[op - 7]; + } + while (n--) { + *addr_to_adjust++ += dest; + } + } +} + #endif STATIC int read_byte(mp_reader_t *reader) { @@ -285,20 +302,28 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { } } -STATIC void load_prelude(mp_reader_t *reader, byte **ip, byte **ip2, bytecode_prelude_t *prelude) { - prelude->n_state = read_uint(reader, ip); - prelude->n_exc_stack = read_uint(reader, ip); - read_bytes(reader, *ip, 4); - prelude->scope_flags = *(*ip)++; - prelude->n_pos_args = *(*ip)++; - prelude->n_kwonly_args = *(*ip)++; - prelude->n_def_pos_args = *(*ip)++; - *ip2 = *ip; - prelude->code_info_size = read_uint(reader, ip2); - read_bytes(reader, *ip2, prelude->code_info_size - (*ip2 - *ip)); - *ip += prelude->code_info_size; - while ((*(*ip)++ = read_byte(reader)) != 255) { - } +STATIC void load_prelude_qstrs(mp_reader_t *reader, qstr_window_t *qw, byte *ip) { + qstr simple_name = load_qstr(reader, qw); + ip[0] = simple_name; ip[1] = simple_name >> 8; + qstr source_file = load_qstr(reader, qw); + ip[2] = source_file; ip[3] = source_file >> 8; +} + +STATIC void load_prelude(mp_reader_t *reader, qstr_window_t *qw, byte **ip, bytecode_prelude_t *prelude) { + // Read in the prelude header + byte *ip_read = *ip; + read_uint(reader, &ip_read); // read in n_state/etc (is effectively a var-uint) + read_uint(reader, &ip_read); // read in n_info/n_cell (is effectively a var-uint) + + // Prelude header has been read into *ip, now decode and extract values from it + extract_prelude((const byte**)ip, prelude); + + // Load qstrs in prelude + load_prelude_qstrs(reader, qw, ip_read); + ip_read += 4; + + // Read remaining code info + read_bytes(reader, ip_read, *ip - ip_read); } STATIC void load_bytecode(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte *ip_top) { @@ -308,12 +333,12 @@ STATIC void load_bytecode(mp_reader_t *reader, qstr_window_t *qw, byte *ip, byte uint f = mp_opcode_format(ip, &sz, false); ++ip; --sz; - if (f == MP_OPCODE_QSTR) { + if (f == MP_BC_FORMAT_QSTR) { qstr qst = load_qstr(reader, qw); *ip++ = qst; *ip++ = qst >> 8; sz -= 2; - } else if (f == MP_OPCODE_VAR_UINT) { + } else if (f == MP_BC_FORMAT_VAR_UINT) { while ((*ip++ = read_byte(reader)) & 0x80) { } } @@ -328,17 +353,16 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { int kind = (kind_len & 3) + MP_CODE_BYTECODE; size_t fun_data_len = kind_len >> 2; - #if !MICROPY_EMIT_NATIVE + #if !MICROPY_EMIT_MACHINE_CODE if (kind != MP_CODE_BYTECODE) { mp_raise_ValueError("incompatible .mpy file"); } #endif uint8_t *fun_data = NULL; - byte *ip2; bytecode_prelude_t prelude = {0}; - #if MICROPY_EMIT_NATIVE - size_t prelude_offset; + #if MICROPY_EMIT_MACHINE_CODE + size_t prelude_offset = 0; mp_uint_t type_sig = 0; size_t n_qstr_link = 0; #endif @@ -349,12 +373,12 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // Load prelude byte *ip = fun_data; - load_prelude(reader, &ip, &ip2, &prelude); + load_prelude(reader, qw, &ip, &prelude); // Load bytecode load_bytecode(reader, qw, ip, fun_data + fun_data_len); - #if MICROPY_EMIT_NATIVE + #if MICROPY_EMIT_MACHINE_CODE } else { // Allocate memory for native data and load it size_t fun_alloc; @@ -372,6 +396,9 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // Generic 16-bit link dest[0] = qst & 0xff; dest[1] = (qst >> 8) & 0xff; + } else if ((off & 3) == 3) { + // Generic, aligned qstr-object link + *(mp_obj_t*)dest = MP_OBJ_NEW_QSTR(qst); } else { // Architecture-specific link arch_link_qstr(dest, (off & 3) == 2, qst); @@ -383,7 +410,9 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // Extract prelude for later use prelude_offset = read_uint(reader, NULL); const byte *ip = fun_data + prelude_offset; - extract_prelude(&ip, (const byte**)&ip2, &prelude); + byte *ip_info = extract_prelude(&ip, &prelude); + // Load qstrs in prelude + load_prelude_qstrs(reader, qw, ip_info); } else { // Load basic scope info for viper and asm prelude.scope_flags = read_uint(reader, NULL); @@ -397,27 +426,31 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { #endif } - if (kind == MP_CODE_BYTECODE || kind == MP_CODE_NATIVE_PY) { - // Load qstrs in prelude - qstr simple_name = load_qstr(reader, qw); - qstr source_file = load_qstr(reader, qw); - ip2[0] = simple_name; ip2[1] = simple_name >> 8; - ip2[2] = source_file; ip2[3] = source_file >> 8; - } - + size_t n_obj = 0; + size_t n_raw_code = 0; mp_uint_t *const_table = NULL; + if (kind != MP_CODE_NATIVE_ASM) { // Load constant table for bytecode, native and viper // Number of entries in constant table - size_t n_obj = read_uint(reader, NULL); - size_t n_raw_code = read_uint(reader, NULL); + n_obj = read_uint(reader, NULL); + n_raw_code = read_uint(reader, NULL); // Allocate constant table size_t n_alloc = prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code; + #if MICROPY_EMIT_MACHINE_CODE if (kind != MP_CODE_BYTECODE) { ++n_alloc; // additional entry for mp_fun_table + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) { + ++n_alloc; // additional entry for rodata + } + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) { + ++n_alloc; // additional entry for BSS + } } + #endif + const_table = m_new(mp_uint_t, n_alloc); mp_uint_t *ct = const_table; @@ -427,10 +460,25 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader, qw)); } - #if MICROPY_EMIT_NATIVE + #if MICROPY_EMIT_MACHINE_CODE if (kind != MP_CODE_BYTECODE) { // Populate mp_fun_table entry - *ct++ = (mp_uint_t)(uintptr_t)mp_fun_table; + *ct++ = (mp_uint_t)(uintptr_t)&mp_fun_table; + + // Allocate and load rodata if needed + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRODATA) { + size_t size = read_uint(reader, NULL); + uint8_t *rodata = m_new(uint8_t, size); + read_bytes(reader, rodata, size); + *ct++ = (uintptr_t)rodata; + } + + // Allocate BSS if needed + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERBSS) { + size_t size = read_uint(reader, NULL); + uint8_t *bss = m_new0(uint8_t, size); + *ct++ = (uintptr_t)bss; + } } #endif @@ -446,6 +494,7 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { // Create raw_code and return it mp_raw_code_t *rc = mp_emit_glue_new_raw_code(); if (kind == MP_CODE_BYTECODE) { + // Assign bytecode to raw code object mp_emit_glue_assign_bytecode(rc, fun_data, #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS fun_data_len, @@ -456,12 +505,20 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader, qstr_window_t *qw) { #endif prelude.scope_flags); - #if MICROPY_EMIT_NATIVE + #if MICROPY_EMIT_MACHINE_CODE } else { + // Relocate and commit code to executable address space + reloc_info_t ri = {reader, const_table}; #if defined(MP_PLAT_COMMIT_EXEC) - fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len); + void *opt_ri = (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) ? &ri : NULL; + fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len, opt_ri); + #else + if (prelude.scope_flags & MP_SCOPE_FLAG_VIPERRELOC) { + mp_native_relocate(&ri, fun_data, (uintptr_t)fun_data); + } #endif + // Assign native code to raw code object mp_emit_glue_assign_native(rc, kind, fun_data, fun_data_len, const_table, #if MICROPY_PERSISTENT_CODE_SAVE @@ -485,9 +542,11 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { || read_uint(reader, NULL) > QSTR_WINDOW_SIZE) { mp_raise_ValueError("incompatible .mpy file"); } - if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE - && MPY_FEATURE_DECODE_ARCH(header[2]) != MPY_FEATURE_ARCH) { - mp_raise_ValueError("incompatible .mpy arch"); + if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE) { + byte arch = MPY_FEATURE_DECODE_ARCH(header[2]); + if (!MPY_FEATURE_ARCH_TEST(arch)) { + mp_raise_ValueError("incompatible .mpy arch"); + } } qstr_window_t qw; qw.idx = 0; @@ -594,11 +653,16 @@ STATIC void save_obj(mp_print_t *print, mp_obj_t o) { } } +STATIC void save_prelude_qstrs(mp_print_t *print, qstr_window_t *qw, const byte *ip) { + save_qstr(print, qw, ip[0] | (ip[1] << 8)); // simple_name + save_qstr(print, qw, ip[2] | (ip[3] << 8)); // source_file +} + STATIC void save_bytecode(mp_print_t *print, qstr_window_t *qw, const byte *ip, const byte *ip_top) { while (ip < ip_top) { size_t sz; uint f = mp_opcode_format(ip, &sz, true); - if (f == MP_OPCODE_QSTR) { + if (f == MP_BC_FORMAT_QSTR) { mp_print_bytes(print, ip, 1); qstr qst = ip[1] | (ip[2] << 8); save_qstr(print, qw, qst); @@ -614,19 +678,23 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q // Save function kind and data length mp_print_uint(print, (rc->fun_data_len << 2) | (rc->kind - MP_CODE_BYTECODE)); - const byte *ip2; bytecode_prelude_t prelude; if (rc->kind == MP_CODE_BYTECODE) { - // Save prelude + // Extract prelude const byte *ip = rc->fun_data; - extract_prelude(&ip, &ip2, &prelude); - size_t prelude_len = ip - (const byte*)rc->fun_data; - const byte *ip_top = (const byte*)rc->fun_data + rc->fun_data_len; - mp_print_bytes(print, rc->fun_data, prelude_len); + const byte *ip_info = extract_prelude(&ip, &prelude); + + // Save prelude + mp_print_bytes(print, rc->fun_data, ip_info - (const byte*)rc->fun_data); + save_prelude_qstrs(print, qstr_window, ip_info); + ip_info += 4; + mp_print_bytes(print, ip_info, ip - ip_info); // Save bytecode + const byte *ip_top = (const byte*)rc->fun_data + rc->fun_data_len; save_bytecode(print, qstr_window, ip, ip_top); + #if MICROPY_EMIT_MACHINE_CODE } else { // LoBo #if MICROPY_EMIT_NATIVE @@ -643,13 +711,16 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q } if (rc->kind == MP_CODE_NATIVE_PY) { - // Save prelude size, and extract prelude for later use + // Save prelude size mp_print_uint(print, rc->prelude_offset); + + // Extract prelude and save qstrs in prelude const byte *ip = (const byte*)rc->fun_data + rc->prelude_offset; - extract_prelude(&ip, &ip2, &prelude); + const byte *ip_info = extract_prelude(&ip, &prelude); + save_prelude_qstrs(print, qstr_window, ip_info); } else { // Save basic scope info for viper and asm - mp_print_uint(print, rc->scope_flags); + mp_print_uint(print, rc->scope_flags & MP_SCOPE_FLAG_ALL_SIG); prelude.n_pos_args = 0; prelude.n_kwonly_args = 0; if (rc->kind == MP_CODE_NATIVE_ASM) { @@ -658,12 +729,7 @@ STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc, qstr_window_t *q } } #endif - } - - if (rc->kind == MP_CODE_BYTECODE || rc->kind == MP_CODE_NATIVE_PY) { - // Save qstrs in prelude - save_qstr(print, qstr_window, ip2[0] | (ip2[1] << 8)); // simple_name - save_qstr(print, qstr_window, ip2[2] | (ip2[3] << 8)); // source_file + #endif } if (rc->kind != MP_CODE_NATIVE_ASM) { @@ -703,9 +769,8 @@ STATIC bool mp_raw_code_has_native(mp_raw_code_t *rc) { } const byte *ip = rc->fun_data; - const byte *ip2; bytecode_prelude_t prelude; - extract_prelude(&ip, &ip2, &prelude); + extract_prelude(&ip, &prelude); const mp_uint_t *const_table = rc->const_table + prelude.n_pos_args + prelude.n_kwonly_args @@ -752,7 +817,7 @@ void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { // here we define mp_raw_code_save_file depending on the port // TODO abstract this away properly -#if defined(__i386__) || defined(__x86_64__) || defined(__unix__) +#if defined(__i386__) || defined(__x86_64__) || defined(_WIN32) || defined(__unix__) #include #include diff --git a/micropython/py/persistentcode.h b/micropython/py/persistentcode.h index 2074c64..8769ef5 100644 --- a/micropython/py/persistentcode.h +++ b/micropython/py/persistentcode.h @@ -31,7 +31,63 @@ #include "py/emitglue.h" // The current version of .mpy files -#define MPY_VERSION 4 +#define MPY_VERSION 5 + +// Macros to encode/decode flags to/from the feature byte +#define MPY_FEATURE_ENCODE_FLAGS(flags) (flags) +#define MPY_FEATURE_DECODE_FLAGS(feat) ((feat) & 3) + +// Macros to encode/decode native architecture to/from the feature byte +#define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2) +#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2) + +// The feature flag bits encode the compile-time config options that +// affect the generate bytecode. +#define MPY_FEATURE_FLAGS ( \ + ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \ + | ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \ + ) +// This is a version of the flags that can be configured at runtime. +#define MPY_FEATURE_FLAGS_DYNAMIC ( \ + ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) << 0) \ + | ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \ + ) + +// Define the host architecture +#if MICROPY_EMIT_X86 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X86) +#elif MICROPY_EMIT_X64 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_X64) +#elif MICROPY_EMIT_THUMB + #if defined(__thumb2__) + #if defined(__ARM_FP) && (__ARM_FP & 8) == 8 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMDP) + #elif defined(__ARM_FP) && (__ARM_FP & 4) == 4 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EMSP) + #else + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7EM) + #endif + #else + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV7M) + #endif + #define MPY_FEATURE_ARCH_TEST(x) (MP_NATIVE_ARCH_ARMV6M <= (x) && (x) <= MPY_FEATURE_ARCH) +#elif MICROPY_EMIT_ARM + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_ARMV6) +#elif MICROPY_EMIT_XTENSA + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) +#elif MICROPY_EMIT_XTENSAWIN + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) +#else + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) +#endif + +#ifndef MPY_FEATURE_ARCH_TEST +#define MPY_FEATURE_ARCH_TEST(x) ((x) == MPY_FEATURE_ARCH) +#endif + +// 16-bit little-endian integer with the second and third bytes of supported .mpy files +#define MPY_FILE_HEADER_INT (MPY_VERSION \ + | (MPY_FEATURE_ENCODE_FLAGS(MPY_FEATURE_FLAGS) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH)) << 8) enum { MP_NATIVE_ARCH_NONE = 0, @@ -44,6 +100,7 @@ enum { MP_NATIVE_ARCH_ARMV7EMSP, MP_NATIVE_ARCH_ARMV7EMDP, MP_NATIVE_ARCH_XTENSA, + MP_NATIVE_ARCH_XTENSAWIN, }; mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader); @@ -53,4 +110,6 @@ mp_raw_code_t *mp_raw_code_load_file(const char *filename); void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print); void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename); +void mp_native_relocate(void *reloc, uint8_t *text, uintptr_t reloc_text); + #endif // MICROPY_INCLUDED_PY_PERSISTENTCODE_H diff --git a/micropython/py/profile.c b/micropython/py/profile.c new file mode 100644 index 0000000..72726cd --- /dev/null +++ b/micropython/py/profile.c @@ -0,0 +1,984 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/profile.h" +#include "py/bc0.h" +#include "py/gc.h" + +#if MICROPY_PY_SYS_SETTRACE + +#define prof_trace_cb MP_STATE_THREAD(prof_trace_callback) + +STATIC uint mp_prof_bytecode_lineno(const mp_raw_code_t *rc, size_t bc) { + const mp_bytecode_prelude_t *prelude = &rc->prelude; + return mp_bytecode_get_source_line(prelude->line_info, bc); +} + +void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude) { + const byte *ip = bytecode; + + MP_BC_PRELUDE_SIG_DECODE(ip); + prelude->n_state = n_state; + prelude->n_exc_stack = n_exc_stack; + prelude->scope_flags = scope_flags; + prelude->n_pos_args = n_pos_args; + prelude->n_kwonly_args = n_kwonly_args; + prelude->n_def_pos_args = n_def_pos_args; + + MP_BC_PRELUDE_SIZE_DECODE(ip); + + prelude->line_info = ip + 4; + prelude->opcodes = ip + n_info + n_cell; + + qstr block_name = ip[0] | (ip[1] << 8); + qstr source_file = ip[2] | (ip[3] << 8); + prelude->qstr_block_name = block_name; + prelude->qstr_source_file = source_file; +} + +/******************************************************************************/ +// code object + +STATIC void code_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_code_t *o = MP_OBJ_TO_PTR(o_in); + const mp_raw_code_t *rc = o->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + mp_printf(print, + "", + prelude->qstr_block_name, + o, + prelude->qstr_source_file, + rc->line_of_definition + ); +} + +STATIC mp_obj_tuple_t* code_consts(const mp_raw_code_t *rc) { + const mp_bytecode_prelude_t *prelude = &rc->prelude; + int start = prelude->n_pos_args + prelude->n_kwonly_args + rc->n_obj; + int stop = prelude->n_pos_args + prelude->n_kwonly_args + rc->n_obj + rc->n_raw_code; + mp_obj_tuple_t *consts = MP_OBJ_TO_PTR(mp_obj_new_tuple(stop - start + 1, NULL)); + + size_t const_no = 0; + for (int i = start; i < stop; ++i) { + mp_obj_t code = mp_obj_new_code((const mp_raw_code_t*)MP_OBJ_TO_PTR(rc->const_table[i])); + if (code == MP_OBJ_NULL) { + m_malloc_fail(sizeof(mp_obj_code_t)); + } + consts->items[const_no++] = code; + } + consts->items[const_no++] = mp_const_none; + + return consts; +} + +STATIC mp_obj_t raw_code_lnotab(const mp_raw_code_t *rc) { + // const mp_bytecode_prelude_t *prelude = &rc->prelude; + uint start = 0; + uint stop = rc->fun_data_len - start; + + uint last_lineno = mp_prof_bytecode_lineno(rc, start); + uint lasti = 0; + + const uint buffer_chunk_size = (stop-start) >> 2; // heuristic magic + uint buffer_size = buffer_chunk_size; + byte *buffer = m_new(byte, buffer_size); + uint buffer_index = 0; + + for (uint i = start; i < stop; ++i) { + uint lineno = mp_prof_bytecode_lineno(rc, i); + size_t line_diff = lineno - last_lineno; + if (line_diff > 0) { + uint instr_diff = (i - start) - lasti; + + assert(instr_diff < 256); + assert(line_diff < 256); + + if (buffer_index + 2 > buffer_size) { + buffer = m_renew(byte, buffer, buffer_size, buffer_size + buffer_chunk_size); + buffer_size = buffer_size + buffer_chunk_size; + } + last_lineno = lineno; + lasti = i - start; + buffer[buffer_index++] = instr_diff; + buffer[buffer_index++] = line_diff; + } + } + + mp_obj_t o = mp_obj_new_bytes(buffer, buffer_index); + m_del(byte, buffer, buffer_size); + return o; +} + +STATIC void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + mp_obj_code_t *o = MP_OBJ_TO_PTR(self_in); + const mp_raw_code_t *rc = o->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + switch(attr) { + case MP_QSTR_co_code: + dest[0] = mp_obj_new_bytes( + (void*)prelude->opcodes, + rc->fun_data_len - (prelude->opcodes - (const byte*)rc->fun_data) + ); + break; + case MP_QSTR_co_consts: + dest[0] = MP_OBJ_FROM_PTR(code_consts(rc)); + break; + case MP_QSTR_co_filename: + dest[0] = MP_OBJ_NEW_QSTR(prelude->qstr_source_file); + break; + case MP_QSTR_co_firstlineno: + dest[0] = MP_OBJ_NEW_SMALL_INT(mp_prof_bytecode_lineno(rc, 0)); + break; + case MP_QSTR_co_name: + dest[0] = MP_OBJ_NEW_QSTR(prelude->qstr_block_name); + break; + case MP_QSTR_co_names: + dest[0] = MP_OBJ_FROM_PTR(o->dict_locals); + break; + case MP_QSTR_co_lnotab: + if (!o->lnotab) { + o->lnotab = raw_code_lnotab(rc); + } + dest[0] = o->lnotab; + break; + } +} + +const mp_obj_type_t mp_type_code = { + { &mp_type_type }, + .name = MP_QSTR_code, + .print = code_print, + .unary_op = mp_generic_unary_op, + .attr = code_attr, +}; + +mp_obj_t mp_obj_new_code(const mp_raw_code_t *rc) { + mp_obj_code_t *o = m_new_obj_maybe(mp_obj_code_t); + if (o == NULL) { + return MP_OBJ_NULL; + } + o->base.type = &mp_type_code; + o->rc = rc; + o->dict_locals = mp_locals_get(); // this is a wrong! how to do this properly? + o->lnotab = MP_OBJ_NULL; + return MP_OBJ_FROM_PTR(o); +} + +/******************************************************************************/ +// frame object + +STATIC void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_frame_t *frame = MP_OBJ_TO_PTR(o_in); + mp_obj_code_t *code = frame->code; + const mp_raw_code_t *rc = code->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + mp_printf(print, + "", + frame, + prelude->qstr_source_file, + frame->lineno, + prelude->qstr_block_name + ); +} + +STATIC void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + + mp_obj_frame_t *o = MP_OBJ_TO_PTR(self_in); + + switch(attr) { + case MP_QSTR_f_back: + dest[0] = mp_const_none; + if (o->code_state->prev_state) { + dest[0] = MP_OBJ_FROM_PTR(o->code_state->prev_state->frame); + } + break; + case MP_QSTR_f_code: + dest[0] = MP_OBJ_FROM_PTR(o->code); + break; + case MP_QSTR_f_globals: + dest[0] = MP_OBJ_FROM_PTR(o->code_state->fun_bc->globals); + break; + case MP_QSTR_f_lasti: + dest[0] = MP_OBJ_NEW_SMALL_INT(o->lasti); + break; + case MP_QSTR_f_lineno: + dest[0] = MP_OBJ_NEW_SMALL_INT(o->lineno); + break; + } +} + +const mp_obj_type_t mp_type_frame = { + { &mp_type_type }, + .name = MP_QSTR_frame, + .print = frame_print, + .unary_op = mp_generic_unary_op, + .attr = frame_attr, +}; + +mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state) { + if (gc_is_locked()) { + return MP_OBJ_NULL; + } + + mp_obj_frame_t *o = m_new_obj_maybe(mp_obj_frame_t); + if (o == NULL) { + return MP_OBJ_NULL; + } + + mp_obj_code_t *code = o->code = MP_OBJ_TO_PTR(mp_obj_new_code(code_state->fun_bc->rc)); + if (code == NULL) { + return MP_OBJ_NULL; + } + + const mp_raw_code_t *rc = code->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + o->code_state = code_state; + o->base.type = &mp_type_frame; + o->back = NULL; + o->code = code; + o->lasti = code_state->ip - prelude->opcodes; + o->lineno = mp_prof_bytecode_lineno(rc, o->lasti); + o->trace_opcodes = false; + o->callback = MP_OBJ_NULL; + + return MP_OBJ_FROM_PTR(o); +} + + +/******************************************************************************/ +// Trace logic + +typedef struct { + struct _mp_obj_frame_t * frame; + mp_obj_t event; + mp_obj_t arg; +} prof_callback_args_t; + +STATIC mp_obj_t mp_prof_callback_invoke(mp_obj_t callback, prof_callback_args_t *args) { + assert(mp_obj_is_callable(callback)); + + mp_prof_is_executing = true; + + mp_obj_t a[3] = {MP_OBJ_FROM_PTR(args->frame), args->event, args->arg}; + mp_obj_t top = mp_call_function_n_kw(callback, 3, 0, a); + + mp_prof_is_executing = false; + + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } + return top; +} + +mp_obj_t mp_prof_settrace(mp_obj_t callback) { + if (mp_obj_is_callable(callback)) { + prof_trace_cb = callback; + } else { + prof_trace_cb = MP_OBJ_NULL; + } + return mp_const_none; +} + +mp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state) { + assert(!mp_prof_is_executing); + + mp_obj_frame_t *frame = MP_OBJ_TO_PTR(mp_obj_new_frame(code_state)); + if (frame == NULL) { + // Couldn't allocate a frame object + return MP_OBJ_NULL; + } + + if (code_state->prev_state && code_state->frame == NULL) { + // We are entering not-yet-traced frame + // which means it's a CALL event (not a GENERATOR) + // so set the function definition line. + const mp_raw_code_t *rc = code_state->fun_bc->rc; + frame->lineno = rc->line_of_definition; + if (!rc->line_of_definition) { + frame->lineno = mp_prof_bytecode_lineno(rc, 0); + } + } + code_state->frame = frame; + + if (!prof_trace_cb) { + return MP_OBJ_NULL; + } + + mp_obj_t top; + prof_callback_args_t _args, *args=&_args; + args->frame = code_state->frame; + + // SETTRACE event CALL + args->event = MP_OBJ_NEW_QSTR(MP_QSTR_call); + args->arg = mp_const_none; + top = mp_prof_callback_invoke(prof_trace_cb, args); + + code_state->frame->callback = mp_obj_is_callable(top) ? top : MP_OBJ_NULL; + + // Invalidate the last executed line number so the LINE trace can trigger after this CALL. + frame->lineno = 0; + + return top; +} + +mp_obj_t mp_prof_frame_update(const mp_code_state_t *code_state) { + mp_obj_frame_t *frame = code_state->frame; + if (frame == NULL) { + // Frame was not allocated (eg because there was no memory available) + return MP_OBJ_NULL; + } + + mp_obj_frame_t *o = frame; + mp_obj_code_t *code = o->code; + const mp_raw_code_t *rc = code->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + + assert(o->code_state == code_state); + + o->lasti = code_state->ip - prelude->opcodes; + o->lineno = mp_prof_bytecode_lineno(rc, o->lasti); + + return MP_OBJ_FROM_PTR(o); +} + +mp_obj_t mp_prof_instr_tick(mp_code_state_t *code_state, bool is_exception) { + // Detect execution recursion + assert(!mp_prof_is_executing); + assert(code_state->frame); + assert(mp_obj_get_type(code_state->frame) == &mp_type_frame); + + // Detect data recursion + assert(code_state != code_state->prev_state); + + mp_obj_t top = mp_const_none; + mp_obj_t callback = code_state->frame->callback; + + prof_callback_args_t _args, *args=&_args; + args->frame = code_state->frame; + args->event = mp_const_none; + args->arg = mp_const_none; + + // Call event's are handled inside mp_prof_frame_enter + + // SETTRACE event EXCEPTION + if (is_exception) { + args->event = MP_OBJ_NEW_QSTR(MP_QSTR_exception); + top = mp_prof_callback_invoke(callback, args); + return top; + } + + // SETTRACE event LINE + const mp_raw_code_t *rc = code_state->fun_bc->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + size_t prev_line_no = args->frame->lineno; + size_t current_line_no = mp_prof_bytecode_lineno(rc, code_state->ip - prelude->opcodes); + if (prev_line_no != current_line_no) { + args->frame->lineno = current_line_no; + args->event = MP_OBJ_NEW_QSTR(MP_QSTR_line); + top = mp_prof_callback_invoke(callback, args); + } + + // SETTRACE event RETURN + const byte *ip = code_state->ip; + if (*ip == MP_BC_RETURN_VALUE || *ip == MP_BC_YIELD_VALUE) { + args->event = MP_OBJ_NEW_QSTR(MP_QSTR_return); + top = mp_prof_callback_invoke(callback, args); + if (code_state->prev_state && *ip == MP_BC_RETURN_VALUE) { + code_state->frame->callback = MP_OBJ_NULL; + } + } + + // SETTRACE event OPCODE + // TODO: frame.f_trace_opcodes=True + if (false) { + args->event = MP_OBJ_NEW_QSTR(MP_QSTR_opcode); + } + + return top; +} + +/******************************************************************************/ +// DEBUG + +// This section is for debugging the settrace feature itself, and is not intended +// to be included in production/release builds. The code structure for this block +// was taken from py/showbc.c and should not be used as a reference. To enable +// this debug feature enable MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE in py/profile.h. +#if MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE + +#include "runtime0.h" + +#define DECODE_UINT { \ + unum = 0; \ + do { \ + unum = (unum << 7) + (*ip & 0x7f); \ + } while ((*ip++ & 0x80) != 0); \ +} +#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0) +#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0) + +#define DECODE_QSTR \ + qst = ip[0] | ip[1] << 8; \ + ip += 2; +#define DECODE_PTR \ + DECODE_UINT; \ + ptr = (const byte*)const_table[unum] +#define DECODE_OBJ \ + DECODE_UINT; \ + obj = (mp_obj_t)const_table[unum] + +typedef struct _mp_dis_instruction_t { + mp_uint_t qstr_opname; + mp_uint_t arg; + mp_obj_t argobj; + mp_obj_t argobjex_cache; +} mp_dis_instruction_t; + +STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_table, mp_dis_instruction_t *instruction) { + mp_uint_t unum; + const byte* ptr; + mp_obj_t obj; + qstr qst; + + instruction->qstr_opname = MP_QSTR_; + instruction->arg = 0; + instruction->argobj= mp_const_none; + instruction->argobjex_cache = mp_const_none; + + switch (*ip++) { + case MP_BC_LOAD_CONST_FALSE: + instruction->qstr_opname = MP_QSTR_LOAD_CONST_FALSE; + break; + + case MP_BC_LOAD_CONST_NONE: + instruction->qstr_opname = MP_QSTR_LOAD_CONST_NONE; + break; + + case MP_BC_LOAD_CONST_TRUE: + instruction->qstr_opname = MP_QSTR_LOAD_CONST_TRUE; + break; + + case MP_BC_LOAD_CONST_SMALL_INT: { + mp_int_t num = 0; + if ((ip[0] & 0x40) != 0) { + // Number is negative + num--; + } + do { + num = (num << 7) | (*ip & 0x7f); + } while ((*ip++ & 0x80) != 0); + instruction->qstr_opname = MP_QSTR_LOAD_CONST_SMALL_INT; + instruction->arg = num; + break; + } + + case MP_BC_LOAD_CONST_STRING: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_CONST_STRING; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_LOAD_CONST_OBJ: + DECODE_OBJ; + instruction->qstr_opname = MP_QSTR_LOAD_CONST_OBJ; + instruction->arg = unum; + instruction->argobj= obj; + break; + + case MP_BC_LOAD_NULL: + instruction->qstr_opname = MP_QSTR_LOAD_NULL; + break; + + case MP_BC_LOAD_FAST_N: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_LOAD_FAST_N; + instruction->arg = unum; + break; + + case MP_BC_LOAD_DEREF: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_LOAD_DEREF; + instruction->arg = unum; + break; + + case MP_BC_LOAD_NAME: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_NAME; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); + } + break; + + case MP_BC_LOAD_GLOBAL: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_GLOBAL; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); + } + break; + + case MP_BC_LOAD_ATTR: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_ATTR; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); + } + break; + + case MP_BC_LOAD_METHOD: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_METHOD; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_LOAD_SUPER_METHOD: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_LOAD_SUPER_METHOD; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_LOAD_BUILD_CLASS: + instruction->qstr_opname = MP_QSTR_LOAD_BUILD_CLASS; + break; + + case MP_BC_LOAD_SUBSCR: + instruction->qstr_opname = MP_QSTR_LOAD_SUBSCR; + break; + + case MP_BC_STORE_FAST_N: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_STORE_FAST_N; + instruction->arg = unum; + break; + + case MP_BC_STORE_DEREF: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_STORE_DEREF; + instruction->arg = unum; + break; + + case MP_BC_STORE_NAME: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_STORE_NAME; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_STORE_GLOBAL: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_STORE_GLOBAL; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_STORE_ATTR: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_STORE_ATTR; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); + } + break; + + case MP_BC_STORE_SUBSCR: + instruction->qstr_opname = MP_QSTR_STORE_SUBSCR; + break; + + case MP_BC_DELETE_FAST: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_DELETE_FAST; + instruction->arg = unum; + break; + + case MP_BC_DELETE_DEREF: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_DELETE_DEREF; + instruction->arg = unum; + break; + + case MP_BC_DELETE_NAME: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_DELETE_NAME; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_DELETE_GLOBAL: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_DELETE_GLOBAL; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_DUP_TOP: + instruction->qstr_opname = MP_QSTR_DUP_TOP; + break; + + case MP_BC_DUP_TOP_TWO: + instruction->qstr_opname = MP_QSTR_DUP_TOP_TWO; + break; + + case MP_BC_POP_TOP: + instruction->qstr_opname = MP_QSTR_POP_TOP; + break; + + case MP_BC_ROT_TWO: + instruction->qstr_opname = MP_QSTR_ROT_TWO; + break; + + case MP_BC_ROT_THREE: + instruction->qstr_opname = MP_QSTR_ROT_THREE; + break; + + case MP_BC_JUMP: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_JUMP; + instruction->arg = unum; + break; + + case MP_BC_POP_JUMP_IF_TRUE: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_POP_JUMP_IF_TRUE; + instruction->arg = unum; + break; + + case MP_BC_POP_JUMP_IF_FALSE: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_POP_JUMP_IF_FALSE; + instruction->arg = unum; + break; + + case MP_BC_JUMP_IF_TRUE_OR_POP: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_JUMP_IF_TRUE_OR_POP; + instruction->arg = unum; + break; + + case MP_BC_JUMP_IF_FALSE_OR_POP: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_JUMP_IF_FALSE_OR_POP; + instruction->arg = unum; + break; + + case MP_BC_SETUP_WITH: + DECODE_ULABEL; // loop-like labels are always forward + instruction->qstr_opname = MP_QSTR_SETUP_WITH; + instruction->arg = unum; + break; + + case MP_BC_WITH_CLEANUP: + instruction->qstr_opname = MP_QSTR_WITH_CLEANUP; + break; + + case MP_BC_UNWIND_JUMP: + DECODE_SLABEL; + instruction->qstr_opname = MP_QSTR_UNWIND_JUMP; + instruction->arg = unum; + break; + + case MP_BC_SETUP_EXCEPT: + DECODE_ULABEL; // except labels are always forward + instruction->qstr_opname = MP_QSTR_SETUP_EXCEPT; + instruction->arg = unum; + break; + + case MP_BC_SETUP_FINALLY: + DECODE_ULABEL; // except labels are always forward + instruction->qstr_opname = MP_QSTR_SETUP_FINALLY; + instruction->arg = unum; + break; + + case MP_BC_END_FINALLY: + // if TOS is an exception, reraises the exception (3 values on TOS) + // if TOS is an integer, does something else + // if TOS is None, just pops it and continues + // else error + instruction->qstr_opname = MP_QSTR_END_FINALLY; + break; + + case MP_BC_GET_ITER: + instruction->qstr_opname = MP_QSTR_GET_ITER; + break; + + case MP_BC_GET_ITER_STACK: + instruction->qstr_opname = MP_QSTR_GET_ITER_STACK; + break; + + case MP_BC_FOR_ITER: + DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward + instruction->qstr_opname = MP_QSTR_FOR_ITER; + instruction->arg = unum; + break; + + case MP_BC_BUILD_TUPLE: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_BUILD_TUPLE; + instruction->arg = unum; + break; + + case MP_BC_BUILD_LIST: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_BUILD_LIST; + instruction->arg = unum; + break; + + case MP_BC_BUILD_MAP: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_BUILD_MAP; + instruction->arg = unum; + break; + + case MP_BC_STORE_MAP: + instruction->qstr_opname = MP_QSTR_STORE_MAP; + break; + + case MP_BC_BUILD_SET: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_BUILD_SET; + instruction->arg = unum; + break; + + #if MICROPY_PY_BUILTINS_SLICE + case MP_BC_BUILD_SLICE: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_BUILD_SLICE; + instruction->arg = unum; + break; + #endif + + case MP_BC_STORE_COMP: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_STORE_COMP; + instruction->arg = unum; + break; + + case MP_BC_UNPACK_SEQUENCE: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_UNPACK_SEQUENCE; + instruction->arg = unum; + break; + + case MP_BC_UNPACK_EX: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_UNPACK_EX; + instruction->arg = unum; + break; + + case MP_BC_MAKE_FUNCTION: + DECODE_PTR; + instruction->qstr_opname = MP_QSTR_MAKE_FUNCTION; + instruction->arg = unum; + instruction->argobj= mp_obj_new_int_from_ull((uint64_t)ptr); + break; + + case MP_BC_MAKE_FUNCTION_DEFARGS: + DECODE_PTR; + instruction->qstr_opname = MP_QSTR_MAKE_FUNCTION_DEFARGS; + instruction->arg = unum; + instruction->argobj= mp_obj_new_int_from_ull((uint64_t)ptr); + break; + + case MP_BC_MAKE_CLOSURE: { + DECODE_PTR; + mp_uint_t n_closed_over = *ip++; + instruction->qstr_opname = MP_QSTR_MAKE_CLOSURE; + instruction->arg = unum; + instruction->argobj= mp_obj_new_int_from_ull((uint64_t)ptr); + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(n_closed_over); + break; + } + + case MP_BC_MAKE_CLOSURE_DEFARGS: { + DECODE_PTR; + mp_uint_t n_closed_over = *ip++; + instruction->qstr_opname = MP_QSTR_MAKE_CLOSURE_DEFARGS; + instruction->arg = unum; + instruction->argobj= mp_obj_new_int_from_ull((uint64_t)ptr); + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(n_closed_over); + break; + } + + case MP_BC_CALL_FUNCTION: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_CALL_FUNCTION; + instruction->arg = unum & 0xff; + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); + break; + + case MP_BC_CALL_FUNCTION_VAR_KW: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_CALL_FUNCTION_VAR_KW; + instruction->arg = unum & 0xff; + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); + break; + + case MP_BC_CALL_METHOD: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_CALL_METHOD; + instruction->arg = unum & 0xff; + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); + break; + + case MP_BC_CALL_METHOD_VAR_KW: + DECODE_UINT; + instruction->qstr_opname = MP_QSTR_CALL_METHOD_VAR_KW; + instruction->arg = unum & 0xff; + instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); + break; + + case MP_BC_RETURN_VALUE: + instruction->qstr_opname = MP_QSTR_RETURN_VALUE; + break; + + case MP_BC_RAISE_LAST: + instruction->qstr_opname = MP_QSTR_RAISE_LAST; + break; + + case MP_BC_RAISE_OBJ: + instruction->qstr_opname = MP_QSTR_RAISE_OBJ; + break; + + case MP_BC_RAISE_FROM: + instruction->qstr_opname = MP_QSTR_RAISE_FROM; + break; + + case MP_BC_YIELD_VALUE: + instruction->qstr_opname = MP_QSTR_YIELD_VALUE; + break; + + case MP_BC_YIELD_FROM: + instruction->qstr_opname = MP_QSTR_YIELD_FROM; + break; + + case MP_BC_IMPORT_NAME: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_IMPORT_NAME; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_IMPORT_FROM: + DECODE_QSTR; + instruction->qstr_opname = MP_QSTR_IMPORT_FROM; + instruction->arg = qst; + instruction->argobj= MP_OBJ_NEW_QSTR(qst); + break; + + case MP_BC_IMPORT_STAR: + instruction->qstr_opname = MP_QSTR_IMPORT_STAR; + break; + + default: + if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) { + instruction->qstr_opname = MP_QSTR_LOAD_CONST_SMALL_INT; + instruction->arg = (mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16; + } else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) { + instruction->qstr_opname = MP_QSTR_LOAD_FAST; + instruction->arg = (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI; + } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) { + instruction->qstr_opname = MP_QSTR_STORE_FAST; + instruction->arg = (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI; + } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) { + instruction->qstr_opname = MP_QSTR_UNARY_OP; + instruction->arg = (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI; + } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) { + mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI; + instruction->qstr_opname = MP_QSTR_BINARY_OP; + instruction->arg = op; + } else { + mp_printf(&mp_plat_print, "code %p, opcode 0x%02x not implemented\n", ip-1, ip[-1]); + assert(0); + return ip; + } + break; + } + + return ip; +} + +void mp_prof_print_instr(const byte* ip, mp_code_state_t *code_state) { + mp_dis_instruction_t _instruction, *instruction = &_instruction; + mp_prof_opcode_decode(ip, code_state->fun_bc->rc->const_table, instruction); + const mp_raw_code_t *rc = code_state->fun_bc->rc; + const mp_bytecode_prelude_t *prelude = &rc->prelude; + + mp_uint_t offset = ip - prelude->opcodes; + mp_printf(&mp_plat_print, "instr"); + + /* long path */ if (1) { + mp_printf(&mp_plat_print, + "@0x%p:%q:%q+0x%04x:%d", + ip, + prelude->qstr_source_file, + prelude->qstr_block_name, + offset, + mp_prof_bytecode_lineno(rc, offset) + ); + } + + /* bytecode */ if (0) { + mp_printf(&mp_plat_print, " %02x %02x %02x %02x", ip[0], ip[1], ip[2], ip[3]); + } + + mp_printf(&mp_plat_print, " 0x%02x %q [%d]", *ip, instruction->qstr_opname, instruction->arg); + + if (instruction->argobj != mp_const_none) { + mp_printf(&mp_plat_print, " $"); + mp_obj_print_helper(&mp_plat_print, instruction->argobj, PRINT_REPR); + } + if (instruction->argobjex_cache != mp_const_none) { + mp_printf(&mp_plat_print, " #"); + mp_obj_print_helper(&mp_plat_print, instruction->argobjex_cache, PRINT_REPR); + } + + mp_printf(&mp_plat_print, "\n"); +} + +#endif // MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE + +#endif // MICROPY_PY_SYS_SETTRACE diff --git a/micropython/py/profile.h b/micropython/py/profile.h new file mode 100644 index 0000000..0293e26 --- /dev/null +++ b/micropython/py/profile.h @@ -0,0 +1,79 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_PY_PROFILING_H +#define MICROPY_INCLUDED_PY_PROFILING_H + +#include "py/emitglue.h" + +#if MICROPY_PY_SYS_SETTRACE + +#define mp_prof_is_executing MP_STATE_THREAD(prof_callback_is_executing) + +typedef struct _mp_obj_code_t { + mp_obj_base_t base; + const mp_raw_code_t *rc; + mp_obj_dict_t *dict_locals; + mp_obj_t lnotab; +} mp_obj_code_t; + +typedef struct _mp_obj_frame_t { + mp_obj_base_t base; + const mp_code_state_t *code_state; + struct _mp_obj_frame_t *back; + mp_obj_t callback; + mp_obj_code_t *code; + mp_uint_t lasti; + mp_uint_t lineno; + bool trace_opcodes; +} mp_obj_frame_t; + +void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude); + +mp_obj_t mp_obj_new_code(const mp_raw_code_t *rc); +mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state); + +// This is the implementation for the sys.settrace +mp_obj_t mp_prof_settrace(mp_obj_t callback); + +mp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state); +mp_obj_t mp_prof_frame_update(const mp_code_state_t *code_state); + +// For every VM instruction tick this function deduces events from the state +mp_obj_t mp_prof_instr_tick(mp_code_state_t *code_state, bool is_exception); + +// This section is for debugging the settrace feature itself, and is not intended +// to be included in production/release builds. +#define MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE 0 +#if MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE +void mp_prof_print_instr(const byte* ip, mp_code_state_t *code_state); +#define MP_PROF_INSTR_DEBUG_PRINT(current_ip) mp_prof_print_instr((current_ip), code_state) +#else +#define MP_PROF_INSTR_DEBUG_PRINT(current_ip) +#endif + +#endif // MICROPY_PY_SYS_SETTRACE +#endif // MICROPY_INCLUDED_PY_PROFILING_H diff --git a/micropython/py/py.mk b/micropython/py/py.mk index 3d8d849..a792c7e 100644 --- a/micropython/py/py.mk +++ b/micropython/py/py.mk @@ -13,127 +13,19 @@ ifneq ($(QSTR_AUTOGEN_DISABLE),1) QSTR_DEFS_COLLECTED = $(HEADER_BUILD)/qstrdefs.collected.h endif -# Any files listed by this variable will cause a full regeneration of qstrs +# Any files listed by these variables will cause a full regeneration of qstrs +# DEPENDENCIES: included in qstr processing; REQUIREMENTS: not included QSTR_GLOBAL_DEPENDENCIES += $(PY_SRC)/mpconfig.h mpconfigport.h +QSTR_GLOBAL_REQUIREMENTS += $(HEADER_BUILD)/mpversion.h # some code is performance bottleneck and compiled with other optimization options CSUPEROPT = -O3 -# this sets the config file for FatFs -CFLAGS_MOD += -DFFCONF_H=\"lib/oofatfs/ffconf.h\" - -ifeq ($(MICROPY_PY_USSL),1) -CFLAGS_MOD += -DMICROPY_PY_USSL=1 -ifeq ($(MICROPY_SSL_AXTLS),1) -CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I$(TOP)/lib/axtls/ssl -I$(TOP)/lib/axtls/crypto -I$(TOP)/extmod/axtls-include -AXTLS_DIR = lib/axtls -$(BUILD)/$(AXTLS_DIR)/%.o: CFLAGS += -Wno-all -Wno-unused-parameter -Wno-uninitialized -Wno-sign-compare -Wno-old-style-definition $(AXTLS_DEFS_EXTRA) -SRC_MOD += $(addprefix $(AXTLS_DIR)/,\ - ssl/asn1.c \ - ssl/loader.c \ - ssl/tls1.c \ - ssl/tls1_svr.c \ - ssl/tls1_clnt.c \ - ssl/x509.c \ - crypto/aes.c \ - crypto/bigint.c \ - crypto/crypto_misc.c \ - crypto/hmac.c \ - crypto/md5.c \ - crypto/rsa.c \ - crypto/sha1.c \ - ) -else ifeq ($(MICROPY_SSL_MBEDTLS),1) -# Can be overridden by ports which have "builtin" mbedTLS -MICROPY_SSL_MBEDTLS_INCLUDE ?= $(TOP)/lib/mbedtls/include -CFLAGS_MOD += -DMICROPY_SSL_MBEDTLS=1 -I$(MICROPY_SSL_MBEDTLS_INCLUDE) -LDFLAGS_MOD += -L$(TOP)/lib/mbedtls/library -lmbedx509 -lmbedtls -lmbedcrypto -endif -endif - -ifeq ($(MICROPY_PY_LWIP),1) -# A port should add an include path where lwipopts.h can be found (eg extmod/lwip-include) -LWIP_DIR = lib/lwip/src -INC += -I$(TOP)/$(LWIP_DIR)/include -CFLAGS_MOD += -DMICROPY_PY_LWIP=1 -$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS_MOD += -Wno-address -SRC_MOD += extmod/modlwip.c lib/netutils/netutils.c -SRC_MOD += $(addprefix $(LWIP_DIR)/,\ - core/def.c \ - core/dns.c \ - core/inet_chksum.c \ - core/init.c \ - core/ip.c \ - core/mem.c \ - core/memp.c \ - core/netif.c \ - core/pbuf.c \ - core/raw.c \ - core/stats.c \ - core/sys.c \ - core/tcp.c \ - core/tcp_in.c \ - core/tcp_out.c \ - core/timeouts.c \ - core/udp.c \ - core/ipv4/autoip.c \ - core/ipv4/dhcp.c \ - core/ipv4/etharp.c \ - core/ipv4/icmp.c \ - core/ipv4/igmp.c \ - core/ipv4/ip4_addr.c \ - core/ipv4/ip4.c \ - core/ipv4/ip4_frag.c \ - core/ipv6/dhcp6.c \ - core/ipv6/ethip6.c \ - core/ipv6/icmp6.c \ - core/ipv6/inet6.c \ - core/ipv6/ip6_addr.c \ - core/ipv6/ip6.c \ - core/ipv6/ip6_frag.c \ - core/ipv6/mld6.c \ - core/ipv6/nd6.c \ - netif/ethernet.c \ - ) -ifeq ($(MICROPY_PY_LWIP_SLIP),1) -CFLAGS_MOD += -DMICROPY_PY_LWIP_SLIP=1 -SRC_MOD += $(LWIP_DIR)/netif/slipif.c -endif -endif - -ifeq ($(MICROPY_PY_BTREE),1) -BTREE_DIR = lib/berkeley-db-1.xx -BTREE_DEFS = -D__DBINTERFACE_PRIVATE=1 -Dmpool_error=printf -Dabort=abort_ "-Dvirt_fd_t=void*" $(BTREE_DEFS_EXTRA) -INC += -I$(TOP)/$(BTREE_DIR)/PORT/include -SRC_MOD += extmod/modbtree.c -SRC_MOD += $(addprefix $(BTREE_DIR)/,\ -btree/bt_close.c \ -btree/bt_conv.c \ -btree/bt_debug.c \ -btree/bt_delete.c \ -btree/bt_get.c \ -btree/bt_open.c \ -btree/bt_overflow.c \ -btree/bt_page.c \ -btree/bt_put.c \ -btree/bt_search.c \ -btree/bt_seq.c \ -btree/bt_split.c \ -btree/bt_utils.c \ -mpool/mpool.c \ - ) -CFLAGS_MOD += -DMICROPY_PY_BTREE=1 -# we need to suppress certain warnings to get berkeley-db to compile cleanly -# and we have separate BTREE_DEFS so the definitions don't interfere with other source code -$(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS) -$(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS) -endif - # External modules written in C. ifneq ($(USER_C_MODULES),) -# pre-define USERMOD variables as expanded so that variables are immediate +# pre-define USERMOD variables as expanded so that variables are immediate # expanded as they're added to them -SRC_USERMOD := +SRC_USERMOD := CFLAGS_USERMOD := LDFLAGS_USERMOD := $(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \ @@ -154,6 +46,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ nlrx86.o \ nlrx64.o \ nlrthumb.o \ + nlrpowerpc.o \ nlrxtensa.o \ nlrsetjmp.o \ malloc.o \ @@ -184,6 +77,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ asmxtensa.o \ emitnxtensa.o \ emitinlinextensa.o \ + emitnxtensawin.o \ formatfloat.o \ parsenumbase.o \ parsenum.o \ @@ -193,9 +87,11 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ runtime_utils.o \ scheduler.o \ nativeglue.o \ + ringbuf.o \ stackctrl.o \ argcheck.o \ warning.o \ + profile.o \ map.o \ obj.o \ objarray.o \ @@ -306,6 +202,11 @@ PY_EXTMOD_O = $(addprefix $(BUILD)/, $(PY_EXTMOD_O_BASENAME)) # this is a convenience variable for ports that want core, extmod and frozen code PY_O = $(PY_CORE_O) $(PY_EXTMOD_O) +# object file for frozen code specified via a manifest +ifneq ($(FROZEN_MANIFEST),) +PY_O += $(BUILD)/$(BUILD)/frozen_content.o +endif + # object file for frozen files ifneq ($(FROZEN_DIR),) PY_O += $(BUILD)/$(BUILD)/frozen.o @@ -336,6 +237,7 @@ MPCONFIGPORT_MK = $(wildcard mpconfigport.mk) # created before we run the script to generate the .h # Note: we need to protect the qstr names from the preprocessor, so we wrap # the lines in "" and then unwrap after the preprocessor is finished. +# See more information about this process in docs/develop/qstr.rst. $(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) $(PY_SRC)/makeqstrdata.py mpconfigport.h $(MPCONFIGPORT_MK) $(PY_SRC)/mpconfig.h | $(HEADER_BUILD) $(ECHO) "GEN $@" $(Q)$(CAT) $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) | $(SED) 's/^Q(.*)/"&"/' | $(CPP) $(CFLAGS) - | $(SED) 's/^\"\(Q(.*)\)\"/\1/' > $(HEADER_BUILD)/qstrdefs.preprocessed.h @@ -365,3 +267,6 @@ $(PY_BUILD)/vm.o: CFLAGS += $(CSUPEROPT) # http://hg.python.org/cpython/file/b127046831e2/Python/ceval.c#l828 # http://www.emulators.com/docs/nx25_nostradamus.htm #-fno-crossjumping + +# Include rules for extmod related code +#include $(TOP)/extmod/extmod.mk diff --git a/micropython/py/pystack.h b/micropython/py/pystack.h index f46f017..4cb1bb5 100644 --- a/micropython/py/pystack.h +++ b/micropython/py/pystack.h @@ -70,7 +70,6 @@ static inline size_t mp_pystack_limit(void) { return MP_STATE_THREAD(pystack_end) - MP_STATE_THREAD(pystack_start); } - static inline void *mp_local_alloc(size_t n_bytes) { if (MP_STATE_THREAD(pystack_enabled)) return mp_pystack_alloc(n_bytes); return alloca(n_bytes); diff --git a/micropython/py/qstr.c b/micropython/py/qstr.c index e6f8640..29ffcae 100644 --- a/micropython/py/qstr.c +++ b/micropython/py/qstr.c @@ -31,6 +31,7 @@ #include "py/mpstate.h" #include "py/qstr.h" #include "py/gc.h" +#include "py/runtime.h" // NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings) // ultimately we will replace this with a static hash table of some kind @@ -192,12 +193,17 @@ qstr qstr_from_str(const char *str) { } qstr qstr_from_strn(const char *str, size_t len) { - assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))); QSTR_ENTER(); qstr q = qstr_find_strn(str, len); if (q == 0) { // qstr does not exist in interned pool so need to add it + // check that len is not too big + if (len >= (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))) { + QSTR_EXIT(); + mp_raise_msg(&mp_type_RuntimeError, "name too long"); + } + // compute number of bytes needed to intern this string size_t n_bytes = MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1; diff --git a/micropython/py/qstr.h b/micropython/py/qstr.h index f4375ee..8153ef2 100644 --- a/micropython/py/qstr.h +++ b/micropython/py/qstr.h @@ -35,7 +35,7 @@ // Note: it would be possible to define MP_QSTR_xxx as qstr_from_str_static("xxx") // for qstrs that are referenced this way, but you don't want to have them in ROM. -// first entry in enum will be MP_QSTR_NULL=0, which indicates invalid/no qstr +// first entry in enum will be MP_QSTRnull=0, which indicates invalid/no qstr enum { #ifndef NO_QSTR #define QDEF(id, str) id, @@ -61,7 +61,7 @@ typedef struct _qstr_pool_t { void qstr_init(void); mp_uint_t qstr_compute_hash(const byte *data, size_t len); -qstr qstr_find_strn(const char *str, size_t str_len); // returns MP_QSTR_NULL if not found +qstr qstr_find_strn(const char *str, size_t str_len); // returns MP_QSTRnull if not found qstr qstr_from_str(const char *str); qstr qstr_from_strn(const char *str, size_t len); diff --git a/micropython/py/repl.c b/micropython/py/repl.c index da0fefb..9389b34 100644 --- a/micropython/py/repl.c +++ b/micropython/py/repl.c @@ -159,7 +159,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print if (str < top) { // a complete word, lookup in current object qstr q = qstr_find_strn(s_start, s_len); - if (q == MP_QSTR_NULL) { + if (q == MP_QSTRnull) { // lookup will fail return 0; } diff --git a/micropython/py/ringbuf.c b/micropython/py/ringbuf.c new file mode 100644 index 0000000..83887b3 --- /dev/null +++ b/micropython/py/ringbuf.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "ringbuf.h" + +int ringbuf_get16(ringbuf_t *r) { + int v = ringbuf_peek16(r); + if (v == -1) { + return v; + } + r->iget += 2; + if (r->iget >= r->size) { + r->iget -= r->size; + } + return v; +} + +int ringbuf_peek16(ringbuf_t *r) { + if (r->iget == r->iput) { + return -1; + } + uint32_t iget_a = r->iget + 1; + if (iget_a == r->size) { + iget_a = 0; + } + if (iget_a == r->iput) { + return -1; + } + return (r->buf[r->iget] << 8) | (r->buf[iget_a]); +} + +int ringbuf_put16(ringbuf_t *r, uint16_t v) { + uint32_t iput_a = r->iput + 1; + if (iput_a == r->size) { + iput_a = 0; + } + if (iput_a == r->iget) { + return -1; + } + uint32_t iput_b = iput_a + 1; + if (iput_b == r->size) { + iput_b = 0; + } + if (iput_b == r->iget) { + return -1; + } + r->buf[r->iput] = (v >> 8) & 0xff; + r->buf[iput_a] = v & 0xff; + r->iput = iput_b; + return 0; +} diff --git a/micropython/py/ringbuf.h b/micropython/py/ringbuf.h index b416927..8d4ed16 100644 --- a/micropython/py/ringbuf.h +++ b/micropython/py/ringbuf.h @@ -26,6 +26,9 @@ #ifndef MICROPY_INCLUDED_PY_RINGBUF_H #define MICROPY_INCLUDED_PY_RINGBUF_H +#include +#include + typedef struct _ringbuf_t { uint8_t *buf; uint16_t size; @@ -37,7 +40,7 @@ typedef struct _ringbuf_t { // byte buf_array[N]; // ringbuf_t buf = {buf_array, sizeof(buf_array)}; -// Dynamic initialization. This creates root pointer! +// Dynamic initialization. This needs to become findable as a root pointer! #define ringbuf_alloc(r, sz) \ { \ (r)->buf = m_new(uint8_t, sz); \ @@ -69,4 +72,17 @@ static inline int ringbuf_put(ringbuf_t *r, uint8_t v) { return 0; } +static inline size_t ringbuf_free(ringbuf_t *r) { + return (r->size + r->iget - r->iput - 1) % r->size; +} + +static inline size_t ringbuf_avail(ringbuf_t *r) { + return (r->size + r->iput - r->iget) % r->size; +} + +// Note: big-endian. No-op if not enough room available for both bytes. +int ringbuf_get16(ringbuf_t *r); +int ringbuf_peek16(ringbuf_t *r); +int ringbuf_put16(ringbuf_t *r, uint16_t v); + #endif // MICROPY_INCLUDED_PY_RINGBUF_H diff --git a/micropython/py/runtime.c b/micropython/py/runtime.c index b1cee31..9436e66 100644 --- a/micropython/py/runtime.c +++ b/micropython/py/runtime.c @@ -90,6 +90,9 @@ void mp_init(void) { #if MICROPY_ENABLE_COMPILER // optimization disabled by default MP_STATE_VM(mp_optimise_value) = 0; + #if MICROPY_EMIT_NATIVE + MP_STATE_VM(default_emit_opt) = MP_EMIT_OPT_NONE; + #endif #endif // init global module dict @@ -98,8 +101,6 @@ void mp_init(void) { // initialise the __main__ module mp_obj_dict_init(&MP_STATE_VM(dict_main), 1); mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(dict_main)), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); - // LoBo: set globals depending on which MicroPython instance is running - mp_module___main__.globals = (mp_obj_dict_t*)&MP_STATE_VM(dict_main); // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) mp_locals_set(&MP_STATE_VM(dict_main)); @@ -122,6 +123,20 @@ void mp_init(void) { MP_STATE_VM(vfs_mount_table) = NULL; #endif + #if MICROPY_PY_SYS_ATEXIT + MP_STATE_VM(sys_exitfunc) = mp_const_none; + #endif + + #if MICROPY_PY_SYS_SETTRACE + MP_STATE_THREAD(prof_trace_callback) = MP_OBJ_NULL; + MP_STATE_THREAD(prof_callback_is_executing) = false; + MP_STATE_THREAD(current_code_state) = NULL; + #endif + + #if MICROPY_PY_BLUETOOTH + MP_STATE_VM(bluetooth) = MP_OBJ_NULL; + #endif + #if MICROPY_PY_THREAD_GIL mp_thread_mutex_init(&MP_STATE_VM(gil_mutex)); #endif @@ -558,16 +573,17 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { } #if MICROPY_PY_REVERSE_SPECIAL_METHODS - if (op >= MP_BINARY_OP_OR && op <= MP_BINARY_OP_REVERSE_POWER) { + if (op >= MP_BINARY_OP_OR && op <= MP_BINARY_OP_POWER) { mp_obj_t t = rhs; rhs = lhs; lhs = t; - if (op <= MP_BINARY_OP_POWER) { - op += MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR; - goto generic_binary_op; - } - + op += MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR; + goto generic_binary_op; + } else if (op >= MP_BINARY_OP_REVERSE_OR) { // Convert __rop__ back to __op__ for error message + mp_obj_t t = rhs; + rhs = lhs; + lhs = t; op -= MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR; } #endif @@ -597,7 +613,6 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { zero_division: mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero"); - return mp_const_none; // LoBo: supress compiler warning } @@ -1313,7 +1328,12 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th // will be propagated up. This behavior is approved by test_pep380.py // test_delegation_of_close_to_non_generator(), // test_delegating_throw_to_non_generator() - *ret_val = mp_make_raise_obj(throw_value); + if (mp_obj_exception_match(throw_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + // PEP479: if StopIteration is raised inside a generator it is replaced with RuntimeError + *ret_val = mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator raised StopIteration"); + } else { + *ret_val = mp_make_raise_obj(throw_value); + } return MP_VM_RETURN_EXCEPTION; } } @@ -1346,7 +1366,17 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { args[3] = fromlist; args[4] = level; - // TODO lookup __import__ and call that instead of going straight to builtin implementation + #if MICROPY_CAN_OVERRIDE_BUILTINS + // Lookup __import__ and call that if it exists + mp_obj_dict_t *bo_dict = MP_STATE_VM(mp_module_builtins_override_dict); + if (bo_dict != NULL) { + mp_map_elem_t *import = mp_map_lookup(&bo_dict->map, MP_OBJ_NEW_QSTR(MP_QSTR___import__), MP_MAP_LOOKUP); + if (import != NULL) { + return mp_call_function_n_kw(import->value, 5, 0, args); + } + } + #endif + return mp_builtin___import__(5, args); } @@ -1418,7 +1448,6 @@ void mp_import_all(mp_obj_t module) { #if MICROPY_ENABLE_COMPILER -// this is implemented in this file so it can optimise access to locals/globals mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_input_kind, mp_obj_dict_t *globals, mp_obj_dict_t *locals) { // save context mp_obj_dict_t *volatile old_globals = mp_globals_get(); @@ -1432,7 +1461,7 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i if (nlr_push(&nlr) == 0) { qstr source_name = lex->source_name; mp_parse_tree_t parse_tree = mp_parse(lex, parse_input_kind); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false); mp_obj_t ret; if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) { diff --git a/micropython/py/runtime.h b/micropython/py/runtime.h index 0eb15d4..b54b17b 100644 --- a/micropython/py/runtime.h +++ b/micropython/py/runtime.h @@ -151,7 +151,6 @@ mp_obj_t mp_import_from(mp_obj_t module, qstr name); void mp_import_all(mp_obj_t module); NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg); -//NORETURN void nlr_raise_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); NORETURN void mp_raise_ValueError(const char *msg); NORETURN void mp_raise_TypeError(const char *msg); NORETURN void mp_raise_NotImplementedError(const char *msg); @@ -172,9 +171,6 @@ NORETURN void mp_raise_recursion_depth(void); int mp_native_type_from_qstr(qstr qst); mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type); mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type); -mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals); -mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args); -void mp_native_raise(mp_obj_t o); #define mp_sys_path (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_path_obj))) #define mp_sys_argv (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_argv_obj))) diff --git a/micropython/py/runtime0.h b/micropython/py/runtime0.h index efd4391..e6eeff9 100644 --- a/micropython/py/runtime0.h +++ b/micropython/py/runtime0.h @@ -28,13 +28,17 @@ // The first four must fit in 8 bits, see emitbc.c // The remaining must fit in 16 bits, see scope.h -#define MP_SCOPE_FLAG_VARARGS (0x01) +#define MP_SCOPE_FLAG_ALL_SIG (0x0f) +#define MP_SCOPE_FLAG_GENERATOR (0x01) #define MP_SCOPE_FLAG_VARKEYWORDS (0x02) -#define MP_SCOPE_FLAG_GENERATOR (0x04) +#define MP_SCOPE_FLAG_VARARGS (0x04) #define MP_SCOPE_FLAG_DEFKWARGS (0x08) #define MP_SCOPE_FLAG_REFGLOBALS (0x10) // used only if native emitter enabled #define MP_SCOPE_FLAG_HASCONSTS (0x20) // used only if native emitter enabled -#define MP_SCOPE_FLAG_VIPERRET_POS (6) // 3 bits used for viper return type +#define MP_SCOPE_FLAG_VIPERRET_POS (6) // 3 bits used for viper return type, to pass from compiler to native emitter +#define MP_SCOPE_FLAG_VIPERRELOC (0x10) // used only when loading viper from .mpy +#define MP_SCOPE_FLAG_VIPERRODATA (0x20) // used only when loading viper from .mpy +#define MP_SCOPE_FLAG_VIPERBSS (0x40) // used only when loading viper from .mpy // types for native (viper) function signature #define MP_NATIVE_TYPE_OBJ (0x00) @@ -46,6 +50,18 @@ #define MP_NATIVE_TYPE_PTR16 (0x06) #define MP_NATIVE_TYPE_PTR32 (0x07) +// Bytecode and runtime boundaries for unary ops +#define MP_UNARY_OP_NUM_BYTECODE (MP_UNARY_OP_NOT + 1) +#define MP_UNARY_OP_NUM_RUNTIME (MP_UNARY_OP_SIZEOF + 1) + +// Bytecode and runtime boundaries for binary ops +#define MP_BINARY_OP_NUM_BYTECODE (MP_BINARY_OP_POWER + 1) +#if MICROPY_PY_REVERSE_SPECIAL_METHODS +#define MP_BINARY_OP_NUM_RUNTIME (MP_BINARY_OP_REVERSE_POWER + 1) +#else +#define MP_BINARY_OP_NUM_RUNTIME (MP_BINARY_OP_CONTAINS + 1) +#endif + typedef enum { // These ops may appear in the bytecode. Changing this group // in any way requires changing the bytecode version. @@ -55,22 +71,19 @@ typedef enum { MP_UNARY_OP_NOT, // Following ops cannot appear in the bytecode - MP_UNARY_OP_NUM_BYTECODE, - - MP_UNARY_OP_BOOL = MP_UNARY_OP_NUM_BYTECODE, // __bool__ + MP_UNARY_OP_BOOL, // __bool__ MP_UNARY_OP_LEN, // __len__ MP_UNARY_OP_HASH, // __hash__; must return a small int MP_UNARY_OP_ABS, // __abs__ MP_UNARY_OP_INT, // __int__ MP_UNARY_OP_SIZEOF, // for sys.getsizeof() - - MP_UNARY_OP_NUM_RUNTIME, } mp_unary_op_t; -// Note: the first 9+12+12 of these are used in bytecode and changing -// them requires changing the bytecode version. typedef enum { - // 9 relational operations, should return a bool + // The following 9+13+13 ops are used in bytecode and changing + // them requires changing the bytecode version. + + // 9 relational operations, should return a bool; order of first 6 matches corresponding mp_token_kind_t MP_BINARY_OP_LESS, MP_BINARY_OP_MORE, MP_BINARY_OP_EQUAL, @@ -81,7 +94,7 @@ typedef enum { MP_BINARY_OP_IS, MP_BINARY_OP_EXCEPTION_MATCH, - // 12 inplace arithmetic operations + // 13 inplace arithmetic operations; order matches corresponding mp_token_kind_t MP_BINARY_OP_INPLACE_OR, MP_BINARY_OP_INPLACE_XOR, MP_BINARY_OP_INPLACE_AND, @@ -90,12 +103,13 @@ typedef enum { MP_BINARY_OP_INPLACE_ADD, MP_BINARY_OP_INPLACE_SUBTRACT, MP_BINARY_OP_INPLACE_MULTIPLY, + MP_BINARY_OP_INPLACE_MAT_MULTIPLY, MP_BINARY_OP_INPLACE_FLOOR_DIVIDE, MP_BINARY_OP_INPLACE_TRUE_DIVIDE, MP_BINARY_OP_INPLACE_MODULO, MP_BINARY_OP_INPLACE_POWER, - // 12 normal arithmetic operations + // 13 normal arithmetic operations; order matches corresponding mp_token_kind_t MP_BINARY_OP_OR, MP_BINARY_OP_XOR, MP_BINARY_OP_AND, @@ -104,6 +118,7 @@ typedef enum { MP_BINARY_OP_ADD, MP_BINARY_OP_SUBTRACT, MP_BINARY_OP_MULTIPLY, + MP_BINARY_OP_MAT_MULTIPLY, MP_BINARY_OP_FLOOR_DIVIDE, MP_BINARY_OP_TRUE_DIVIDE, MP_BINARY_OP_MODULO, @@ -111,11 +126,18 @@ typedef enum { // Operations below this line don't appear in bytecode, they // just identify special methods. - MP_BINARY_OP_NUM_BYTECODE, - // MP_BINARY_OP_REVERSE_* must follow immediately after MP_BINARY_OP_* -#if MICROPY_PY_REVERSE_SPECIAL_METHODS - MP_BINARY_OP_REVERSE_OR = MP_BINARY_OP_NUM_BYTECODE, + // This is not emitted by the compiler but is supported by the runtime. + // It must follow immediately after MP_BINARY_OP_POWER. + MP_BINARY_OP_DIVMOD, + + // The runtime will convert MP_BINARY_OP_IN to this operator with swapped args. + // A type should implement this containment operator instead of MP_BINARY_OP_IN. + MP_BINARY_OP_CONTAINS, + + // 13 MP_BINARY_OP_REVERSE_* operations must be in the same order as MP_BINARY_OP_*, + // and be the last ones supported by the runtime. + MP_BINARY_OP_REVERSE_OR, MP_BINARY_OP_REVERSE_XOR, MP_BINARY_OP_REVERSE_AND, MP_BINARY_OP_REVERSE_LSHIFT, @@ -123,88 +145,15 @@ typedef enum { MP_BINARY_OP_REVERSE_ADD, MP_BINARY_OP_REVERSE_SUBTRACT, MP_BINARY_OP_REVERSE_MULTIPLY, + MP_BINARY_OP_REVERSE_MAT_MULTIPLY, MP_BINARY_OP_REVERSE_FLOOR_DIVIDE, MP_BINARY_OP_REVERSE_TRUE_DIVIDE, MP_BINARY_OP_REVERSE_MODULO, MP_BINARY_OP_REVERSE_POWER, -#endif - - // This is not emitted by the compiler but is supported by the runtime - MP_BINARY_OP_DIVMOD - #if !MICROPY_PY_REVERSE_SPECIAL_METHODS - = MP_BINARY_OP_NUM_BYTECODE - #endif - , - - // The runtime will convert MP_BINARY_OP_IN to this operator with swapped args. - // A type should implement this containment operator instead of MP_BINARY_OP_IN. - MP_BINARY_OP_CONTAINS, - - MP_BINARY_OP_NUM_RUNTIME, // These 2 are not supported by the runtime and must be synthesised by the emitter MP_BINARY_OP_NOT_IN, MP_BINARY_OP_IS_NOT, } mp_binary_op_t; -typedef enum { - MP_F_CONST_NONE_OBJ = 0, - MP_F_CONST_FALSE_OBJ, - MP_F_CONST_TRUE_OBJ, - MP_F_CONVERT_OBJ_TO_NATIVE, - MP_F_CONVERT_NATIVE_TO_OBJ, - MP_F_NATIVE_SWAP_GLOBALS, - MP_F_LOAD_NAME, - MP_F_LOAD_GLOBAL, - MP_F_LOAD_BUILD_CLASS, - MP_F_LOAD_ATTR, - MP_F_LOAD_METHOD, - MP_F_LOAD_SUPER_METHOD, - MP_F_STORE_NAME, - MP_F_STORE_GLOBAL, - MP_F_STORE_ATTR, - MP_F_OBJ_SUBSCR, - MP_F_OBJ_IS_TRUE, - MP_F_UNARY_OP, - MP_F_BINARY_OP, - MP_F_BUILD_TUPLE, - MP_F_BUILD_LIST, - MP_F_LIST_APPEND, - MP_F_BUILD_MAP, - MP_F_STORE_MAP, -#if MICROPY_PY_BUILTINS_SET - MP_F_STORE_SET, - MP_F_BUILD_SET, -#endif - MP_F_MAKE_FUNCTION_FROM_RAW_CODE, - MP_F_NATIVE_CALL_FUNCTION_N_KW, - MP_F_CALL_METHOD_N_KW, - MP_F_CALL_METHOD_N_KW_VAR, - MP_F_NATIVE_GETITER, - MP_F_NATIVE_ITERNEXT, - MP_F_NLR_PUSH, - MP_F_NLR_POP, - MP_F_NATIVE_RAISE, - MP_F_IMPORT_NAME, - MP_F_IMPORT_FROM, - MP_F_IMPORT_ALL, -#if MICROPY_PY_BUILTINS_SLICE - MP_F_NEW_SLICE, -#endif - MP_F_UNPACK_SEQUENCE, - MP_F_UNPACK_EX, - MP_F_DELETE_NAME, - MP_F_DELETE_GLOBAL, - MP_F_NEW_CELL, - MP_F_MAKE_CLOSURE_FROM_RAW_CODE, - MP_F_ARG_CHECK_NUM_SIG, - MP_F_SETUP_CODE_STATE, - MP_F_SMALL_INT_FLOOR_DIVIDE, - MP_F_SMALL_INT_MODULO, - MP_F_NATIVE_YIELD_FROM, - MP_F_NUMBER_OF, -} mp_fun_kind_t; - -extern const void *const mp_fun_table[MP_F_NUMBER_OF]; - #endif // MICROPY_INCLUDED_PY_RUNTIME0_H diff --git a/micropython/py/scheduler.c b/micropython/py/scheduler.c index 5edff45..e7cbb52 100644 --- a/micropython/py/scheduler.c +++ b/micropython/py/scheduler.c @@ -65,7 +65,7 @@ void mp_handle_pending(void) { void mp_handle_pending_tail(mp_uint_t atomic_state) { MP_STATE_VM(sched_state) = MP_SCHED_LOCKED; if (!mp_sched_empty()) { - mp_sched_item_t item = MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_idx)]; + mp_sched_item_t item = MP_STATE_VM(sched_queue)[MP_STATE_VM(sched_idx)]; MP_STATE_VM(sched_idx) = IDX_MASK(MP_STATE_VM(sched_idx) + 1); --MP_STATE_VM(sched_len); MICROPY_END_ATOMIC_SECTION(atomic_state); @@ -107,11 +107,11 @@ bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg) { MP_STATE_VM(sched_state) = MP_SCHED_PENDING; } uint8_t iput = IDX_MASK(MP_STATE_VM(sched_idx) + MP_STATE_VM(sched_len)++); - MP_STATE_VM(sched_stack)[iput].func = function; - MP_STATE_VM(sched_stack)[iput].arg = arg; + MP_STATE_VM(sched_queue)[iput].func = function; + MP_STATE_VM(sched_queue)[iput].arg = arg; ret = true; } else { - // schedule stack is full + // schedule queue is full ret = false; } MICROPY_END_ATOMIC_SECTION(atomic_state); diff --git a/micropython/py/sequence.c b/micropython/py/sequence.c index c66fde9..4c19fc6 100644 --- a/micropython/py/sequence.c +++ b/micropython/py/sequence.c @@ -165,7 +165,7 @@ bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte * size_t min_len = len1 < len2 ? len1 : len2; int res = memcmp(data1, data2, min_len); if (op == MP_BINARY_OP_EQUAL) { - // If we are checking for equality, here're the answer + // If we are checking for equality, here's the answer return res == 0; } if (res < 0) { diff --git a/micropython/py/showbc.c b/micropython/py/showbc.c index b9024b7..d154511 100644 --- a/micropython/py/showbc.c +++ b/micropython/py/showbc.c @@ -83,17 +83,10 @@ const mp_uint_t *mp_showbc_const_table; void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const mp_uint_t *const_table) { mp_showbc_code_start = ip; - // get bytecode parameters - mp_uint_t n_state = mp_decode_uint(&ip); - mp_uint_t n_exc_stack = mp_decode_uint(&ip); - /*mp_uint_t scope_flags =*/ ip++; - mp_uint_t n_pos_args = *ip++; - mp_uint_t n_kwonly_args = *ip++; - /*mp_uint_t n_def_pos_args =*/ ip++; - + // Decode prelude + MP_BC_PRELUDE_SIG_DECODE(ip); + MP_BC_PRELUDE_SIZE_DECODE(ip); const byte *code_info = ip; - mp_uint_t code_info_size = mp_decode_uint(&code_info); - ip += code_info_size; #if MICROPY_PERSISTENT_CODE qstr block_name = code_info[0] | (code_info[1] << 8); @@ -107,7 +100,9 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const m qstr_str(source_file), qstr_str(block_name), descr, mp_showbc_code_start, len); // raw bytecode dump - printf("Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n", code_info_size, len - code_info_size); + size_t prelude_size = ip - mp_showbc_code_start + n_info + n_cell; + printf("Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n", + prelude_size, len - prelude_size); for (mp_uint_t i = 0; i < len; i++) { if (i > 0 && i % 16 == 0) { printf("\n"); @@ -123,24 +118,21 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const m } printf("\n"); - printf("(N_STATE " UINT_FMT ")\n", n_state); - printf("(N_EXC_STACK " UINT_FMT ")\n", n_exc_stack); + printf("(N_STATE %u)\n", (unsigned)n_state); + printf("(N_EXC_STACK %u)\n", (unsigned)n_exc_stack); - // for printing line number info - const byte *bytecode_start = ip; + // skip over code_info + ip += n_info; // bytecode prelude: initialise closed over variables - { - uint local_num; - while ((local_num = *ip++) != 255) { - printf("(INIT_CELL %u)\n", local_num); - } - len -= ip - mp_showbc_code_start; + for (size_t i = 0; i < n_cell; ++i) { + uint local_num = *ip++; + printf("(INIT_CELL %u)\n", local_num); } // print out line number info { - mp_int_t bc = bytecode_start - ip; + mp_int_t bc = 0; mp_uint_t source_line = 1; printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); for (const byte* ci = code_info; *ci;) { @@ -158,7 +150,7 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const m printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); } } - mp_bytecode_print2(ip, len - 0, const_table); + mp_bytecode_print2(ip, len - prelude_size, const_table); } const byte *mp_bytecode_print_str(const byte *ip) { @@ -500,9 +492,16 @@ const byte *mp_bytecode_print_str(const byte *ip) { printf("RETURN_VALUE"); break; - case MP_BC_RAISE_VARARGS: - unum = *ip++; - printf("RAISE_VARARGS " UINT_FMT, unum); + case MP_BC_RAISE_LAST: + printf("RAISE_LAST"); + break; + + case MP_BC_RAISE_OBJ: + printf("RAISE_OBJ"); + break; + + case MP_BC_RAISE_FROM: + printf("RAISE_FROM"); break; case MP_BC_YIELD_VALUE: @@ -540,7 +539,7 @@ const byte *mp_bytecode_print_str(const byte *ip) { mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI; printf("BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op])); } else { - printf("code %p, byte code 0x%02x not implemented\n", ip, ip[-1]); + printf("code %p, byte code 0x%02x not implemented\n", ip - 1, ip[-1]); assert(0); return ip; } diff --git a/micropython/py/stream.h b/micropython/py/stream.h index b6019bb..3ebd4e0 100644 --- a/micropython/py/stream.h +++ b/micropython/py/stream.h @@ -45,10 +45,11 @@ #define MP_STREAM_GET_FILENO (10) // Get fileno of underlying file // These poll ioctl values are compatible with Linux -#define MP_STREAM_POLL_RD (0x0001) -#define MP_STREAM_POLL_WR (0x0004) -#define MP_STREAM_POLL_ERR (0x0008) -#define MP_STREAM_POLL_HUP (0x0010) +#define MP_STREAM_POLL_RD (0x0001) +#define MP_STREAM_POLL_WR (0x0004) +#define MP_STREAM_POLL_ERR (0x0008) +#define MP_STREAM_POLL_HUP (0x0010) +#define MP_STREAM_POLL_NVAL (0x0020) // Argument structure for MP_STREAM_SEEK struct mp_stream_seek_t { diff --git a/micropython/py/vm.c b/micropython/py/vm.c index 784ba97..1d524d1 100644 --- a/micropython/py/vm.c +++ b/micropython/py/vm.c @@ -35,6 +35,7 @@ #include "py/runtime.h" #include "py/bc0.h" #include "py/bc.h" +#include "py/profile.h" #if 0 #define TRACE(ip) printf("sp=%d ", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(ip, 1, code_state->fun_bc->const_table); @@ -109,6 +110,87 @@ exc_sp--; /* pop back to previous exception handler */ \ CLEAR_SYS_EXC_INFO() /* just clear sys.exc_info(), not compliant, but it shouldn't be used in 1st place */ +#define CANCEL_ACTIVE_FINALLY(sp) do { \ + if (mp_obj_is_small_int(sp[-1])) { \ + /* Stack: (..., prev_dest_ip, prev_cause, dest_ip) */ \ + /* Cancel the unwind through the previous finally, replace with current one */ \ + sp[-2] = sp[0]; \ + sp -= 2; \ + } else { \ + assert(sp[-1] == mp_const_none || mp_obj_is_exception_instance(sp[-1])); \ + /* Stack: (..., None/exception, dest_ip) */ \ + /* Silence the finally's exception value (may be None or an exception) */ \ + sp[-1] = sp[0]; \ + --sp; \ + } \ +} while (0) + +#if MICROPY_PY_SYS_SETTRACE + +#define FRAME_SETUP() do { \ + assert(code_state != code_state->prev_state); \ + MP_STATE_THREAD(current_code_state) = code_state; \ + assert(code_state != code_state->prev_state); \ +} while(0) + +#define FRAME_ENTER() do { \ + assert(code_state != code_state->prev_state); \ + code_state->prev_state = MP_STATE_THREAD(current_code_state); \ + assert(code_state != code_state->prev_state); \ + if (!mp_prof_is_executing) { \ + mp_prof_frame_enter(code_state); \ + } \ +} while(0) + +#define FRAME_LEAVE() do { \ + assert(code_state != code_state->prev_state); \ + MP_STATE_THREAD(current_code_state) = code_state->prev_state; \ + assert(code_state != code_state->prev_state); \ +} while(0) + +#define FRAME_UPDATE() do { \ + assert(MP_STATE_THREAD(current_code_state) == code_state); \ + if (!mp_prof_is_executing) { \ + code_state->frame = MP_OBJ_TO_PTR(mp_prof_frame_update(code_state)); \ + } \ +} while(0) + +#define TRACE_TICK(current_ip, current_sp, is_exception) do { \ + assert(code_state != code_state->prev_state); \ + assert(MP_STATE_THREAD(current_code_state) == code_state); \ + if (!mp_prof_is_executing && code_state->frame && MP_STATE_THREAD(prof_trace_callback)) { \ + MP_PROF_INSTR_DEBUG_PRINT(code_state->ip); \ + } \ + if (!mp_prof_is_executing && code_state->frame && code_state->frame->callback) { \ + mp_prof_instr_tick(code_state, is_exception); \ + } \ +} while(0) + +#else // MICROPY_PY_SYS_SETTRACE +#define FRAME_SETUP() +#define FRAME_ENTER() +#define FRAME_LEAVE() +#define FRAME_UPDATE() +#define TRACE_TICK(current_ip, current_sp, is_exception) +#endif // MICROPY_PY_SYS_SETTRACE + +#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE +static inline mp_map_elem_t *mp_map_cached_lookup(mp_map_t *map, qstr qst, uint8_t *idx_cache) { + size_t idx = *idx_cache; + mp_obj_t key = MP_OBJ_NEW_QSTR(qst); + mp_map_elem_t *elem = NULL; + if (idx < map->alloc && map->table[idx].key == key) { + elem = &map->table[idx]; + } else { + elem = mp_map_lookup(map, key, MP_MAP_LOOKUP); + if (elem != NULL) { + *idx_cache = (elem - &map->table[0]) & 0xff; + } + } + return elem; +} +#endif + // fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc) // sp points to bottom of stack which grows up // returns: @@ -129,6 +211,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp #define DISPATCH() do { \ TRACE(ip); \ MARK_EXC_IP_GLOBAL(); \ + TRACE_TICK(ip, sp, false); \ goto *entry_table[*ip++]; \ } while (0) #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check @@ -150,17 +233,24 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp #if MICROPY_STACKLESS run_code_state: ; #endif +FRAME_ENTER(); + +#if MICROPY_STACKLESS +run_code_state_from_return: ; +#endif +FRAME_SETUP(); + // Pointers which are constant for particular invocation of mp_execute_bytecode() mp_obj_t * /*const*/ fastn; mp_exc_stack_t * /*const*/ exc_stack; { - size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); + size_t n_state = code_state->n_state; fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); } // variables that are visible to the exception handler (declared volatile) - mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack + mp_exc_stack_t *volatile exc_sp = MP_CODE_STATE_EXC_SP_IDX_TO_PTR(exc_stack, code_state->exc_sp_idx); // stack grows up, exc_sp points to top of stack #if MICROPY_PY_THREAD_GIL && MICROPY_PY_THREAD_GIL_VM_DIVISOR // This needs to be volatile and outside the VM loop so it persists across handling @@ -180,7 +270,7 @@ run_code_state: ; MICROPY_VM_HOOK_INIT // If we have exception to inject, now that we finish setting up - // execution context, raise it. This works as if RAISE_VARARGS + // execution context, raise it. This works as if MP_BC_RAISE_OBJ // bytecode was executed. // Injecting exc into yield from generator is a special case, // handled by MP_BC_YIELD_FROM itself @@ -199,6 +289,7 @@ run_code_state: ; #else TRACE(ip); MARK_EXC_IP_GLOBAL(); + TRACE_TICK(ip, sp, false); switch (*ip++) { #endif @@ -275,19 +366,14 @@ run_code_state: ; ENTRY(MP_BC_LOAD_NAME): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; - mp_obj_t key = MP_OBJ_NEW_QSTR(qst); - mp_uint_t x = *ip; - if (x < mp_locals_get()->map.alloc && mp_locals_get()->map.table[x].key == key) { - PUSH(mp_locals_get()->map.table[x].value); + mp_map_elem_t *elem = mp_map_cached_lookup(&mp_locals_get()->map, qst, (uint8_t*)ip); + mp_obj_t obj; + if (elem != NULL) { + obj = elem->value; } else { - mp_map_elem_t *elem = mp_map_lookup(&mp_locals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); - if (elem != NULL) { - *(byte*)ip = (elem - &mp_locals_get()->map.table[0]) & 0xff; - PUSH(elem->value); - } else { - PUSH(mp_load_name(MP_OBJ_QSTR_VALUE(key))); - } + obj = mp_load_name(qst); } + PUSH(obj); ip++; DISPATCH(); } @@ -304,19 +390,14 @@ run_code_state: ; ENTRY(MP_BC_LOAD_GLOBAL): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; - mp_obj_t key = MP_OBJ_NEW_QSTR(qst); - mp_uint_t x = *ip; - if (x < mp_globals_get()->map.alloc && mp_globals_get()->map.table[x].key == key) { - PUSH(mp_globals_get()->map.table[x].value); + mp_map_elem_t *elem = mp_map_cached_lookup(&mp_globals_get()->map, qst, (uint8_t*)ip); + mp_obj_t obj; + if (elem != NULL) { + obj = elem->value; } else { - mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); - if (elem != NULL) { - *(byte*)ip = (elem - &mp_globals_get()->map.table[0]) & 0xff; - PUSH(elem->value); - } else { - PUSH(mp_load_global(MP_OBJ_QSTR_VALUE(key))); - } + obj = mp_load_global(qst); } + PUSH(obj); ip++; DISPATCH(); } @@ -324,6 +405,7 @@ run_code_state: ; #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_LOAD_ATTR): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; SET_TOP(mp_load_attr(TOP(), qst)); @@ -331,30 +413,22 @@ run_code_state: ; } #else ENTRY(MP_BC_LOAD_ATTR): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); + mp_map_elem_t *elem = NULL; if (mp_obj_is_instance_type(mp_obj_get_type(top))) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(top); - mp_uint_t x = *ip; - mp_obj_t key = MP_OBJ_NEW_QSTR(qst); - mp_map_elem_t *elem; - if (x < self->members.alloc && self->members.table[x].key == key) { - elem = &self->members.table[x]; - } else { - elem = mp_map_lookup(&self->members, key, MP_MAP_LOOKUP); - if (elem != NULL) { - *(byte*)ip = elem - &self->members.table[0]; - } else { - goto load_attr_cache_fail; - } - } - SET_TOP(elem->value); - ip++; - DISPATCH(); + elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip); } - load_attr_cache_fail: - SET_TOP(mp_load_attr(top, qst)); + mp_obj_t obj; + if (elem != NULL) { + obj = elem->value; + } else { + obj = mp_load_attr(top, qst); + } + SET_TOP(obj); ip++; DISPATCH(); } @@ -416,6 +490,7 @@ run_code_state: ; #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_STORE_ATTR): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_store_attr(sp[0], qst, sp[-1]); @@ -429,31 +504,20 @@ run_code_state: ; // consequence of this is that we can't use MP_MAP_LOOKUP_ADD_IF_NOT_FOUND // in the fast-path below, because that store could override a property. ENTRY(MP_BC_STORE_ATTR): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; + mp_map_elem_t *elem = NULL; mp_obj_t top = TOP(); if (mp_obj_is_instance_type(mp_obj_get_type(top)) && sp[-1] != MP_OBJ_NULL) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(top); - mp_uint_t x = *ip; - mp_obj_t key = MP_OBJ_NEW_QSTR(qst); - mp_map_elem_t *elem; - if (x < self->members.alloc && self->members.table[x].key == key) { - elem = &self->members.table[x]; - } else { - elem = mp_map_lookup(&self->members, key, MP_MAP_LOOKUP); - if (elem != NULL) { - *(byte*)ip = elem - &self->members.table[0]; - } else { - goto store_attr_cache_fail; - } - } + elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip); + } + if (elem != NULL) { elem->value = sp[-1]; - sp -= 2; - ip++; - DISPATCH(); + } else { + mp_store_attr(sp[0], qst, sp[-1]); } - store_attr_cache_fail: - mp_store_attr(sp[0], qst, sp[-1]); sp -= 2; ip++; DISPATCH(); @@ -650,21 +714,28 @@ unwind_jump:; while ((unum & 0x7f) > 0) { unum -= 1; assert(exc_sp >= exc_stack); - if (MP_TAGPTR_TAG1(exc_sp->val_sp) && exc_sp->handler > ip) { - // Getting here the stack looks like: - // (..., X, dest_ip) - // where X is pointed to by exc_sp->val_sp and in the case - // of a "with" block contains the context manager info. - // We're going to run "finally" code as a coroutine - // (not calling it recursively). Set up a sentinel - // on the stack so it can return back to us when it is - // done (when WITH_CLEANUP or END_FINALLY reached). - // The sentinel is the number of exception handlers left to - // unwind, which is a non-negative integer. - PUSH(MP_OBJ_NEW_SMALL_INT(unum)); - ip = exc_sp->handler; // get exception handler byte code address - exc_sp--; // pop exception handler - goto dispatch_loop; // run the exception handler + + if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { + if (exc_sp->handler > ip) { + // Found a finally handler that isn't active; run it. + // Getting here the stack looks like: + // (..., X, dest_ip) + // where X is pointed to by exc_sp->val_sp and in the case + // of a "with" block contains the context manager info. + assert(&sp[-1] == MP_TAGPTR_PTR(exc_sp->val_sp)); + // We're going to run "finally" code as a coroutine + // (not calling it recursively). Set up a sentinel + // on the stack so it can return back to us when it is + // done (when WITH_CLEANUP or END_FINALLY reached). + // The sentinel is the number of exception handlers left to + // unwind, which is a non-negative integer. + PUSH(MP_OBJ_NEW_SMALL_INT(unum)); + ip = exc_sp->handler; + goto dispatch_loop; + } else { + // Found a finally handler that is already active; cancel it. + CANCEL_ACTIVE_FINALLY(sp); + } } POP_EXC_BLOCK(); } @@ -692,9 +763,9 @@ unwind_jump:; // if TOS is None, just pops it and continues // if TOS is an integer, finishes coroutine and returns control to caller // if TOS is an exception, reraises the exception + assert(exc_sp >= exc_stack); + POP_EXC_BLOCK(); if (TOP() == mp_const_none) { - assert(exc_sp >= exc_stack); - POP_EXC_BLOCK(); sp--; } else if (mp_obj_is_small_int(TOP())) { // We finished "finally" coroutine and now dispatch back @@ -739,6 +810,7 @@ unwind_jump:; } ENTRY(MP_BC_FOR_ITER): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward code_state->sp = sp; @@ -754,6 +826,12 @@ unwind_jump:; ip += ulab; // jump to after for-block } else { PUSH(value); // push the next iteration value + #if MICROPY_PY_SYS_SETTRACE + // LINE event should trigger for every iteration so invalidate last trigger + if (code_state->frame) { + code_state->frame->lineno = 0; + } + #endif } DISPATCH(); } @@ -888,6 +966,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_FUNCTION): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional @@ -897,7 +976,7 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); if (MP_STATE_THREAD(pystack_enabled)) { if (new_state == NULL) { @@ -928,6 +1007,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_FUNCTION_VAR_KW): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional @@ -939,13 +1019,18 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); + #if !MICROPY_ENABLE_PYSTACK + // Freeing args at this point does not follow a LIFO order so only do it if + // pystack is not enabled. For pystack, they are freed when code_state is. + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); + #endif if (!MP_STATE_THREAD(pystack_enabled)) { // Freeing args at this point does not follow a LIFO order so only do it if // pystack is not enabled. For pystack, they are freed when code_state is. @@ -977,6 +1062,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_METHOD): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional @@ -986,7 +1072,7 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); size_t n_args = unum & 0xff; size_t n_kw = (unum >> 8) & 0xff; @@ -1021,6 +1107,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_METHOD_VAR_KW): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional @@ -1032,13 +1119,18 @@ unwind_jump:; if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); + #if !MICROPY_ENABLE_PYSTACK + // Freeing args at this point does not follow a LIFO order so only do it if + // pystack is not enabled. For pystack, they are freed when code_state is. + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); + #endif if (!MP_STATE_THREAD(pystack_enabled)) { // Freeing args at this point does not follow a LIFO order so only do it if // pystack is not enabled. For pystack, they are freed when code_state is. @@ -1074,28 +1166,32 @@ unwind_jump:; unwind_return: // Search for and execute finally handlers that aren't already active while (exc_sp >= exc_stack) { - if (MP_TAGPTR_TAG1(exc_sp->val_sp) && exc_sp->handler > ip) { - // Found a finally handler that isn't active. - // Getting here the stack looks like: - // (..., X, [iter0, iter1, ...,] ret_val) - // where X is pointed to by exc_sp->val_sp and in the case - // of a "with" block contains the context manager info. - // There may be 0 or more for-iterators between X and the - // return value, and these must be removed before control can - // pass to the finally code. We simply copy the ret_value down - // over these iterators, if they exist. If they don't then the - // following is a null operation. - mp_obj_t *finally_sp = MP_TAGPTR_PTR(exc_sp->val_sp); - finally_sp[1] = sp[0]; - sp = &finally_sp[1]; - // We're going to run "finally" code as a coroutine - // (not calling it recursively). Set up a sentinel - // on a stack so it can return back to us when it is - // done (when WITH_CLEANUP or END_FINALLY reached). - PUSH(MP_OBJ_NEW_SMALL_INT(-1)); - ip = exc_sp->handler; - POP_EXC_BLOCK(); - goto dispatch_loop; + if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { + if (exc_sp->handler > ip) { + // Found a finally handler that isn't active; run it. + // Getting here the stack looks like: + // (..., X, [iter0, iter1, ...,] ret_val) + // where X is pointed to by exc_sp->val_sp and in the case + // of a "with" block contains the context manager info. + // There may be 0 or more for-iterators between X and the + // return value, and these must be removed before control can + // pass to the finally code. We simply copy the ret_value down + // over these iterators, if they exist. If they don't then the + // following is a null operation. + mp_obj_t *finally_sp = MP_TAGPTR_PTR(exc_sp->val_sp); + finally_sp[1] = sp[0]; + sp = &finally_sp[1]; + // We're going to run "finally" code as a coroutine + // (not calling it recursively). Set up a sentinel + // on a stack so it can return back to us when it is + // done (when WITH_CLEANUP or END_FINALLY reached). + PUSH(MP_OBJ_NEW_SMALL_INT(-1)); + ip = exc_sp->handler; + goto dispatch_loop; + } else { + // Found a finally handler that is already active; cancel it. + CANCEL_ACTIVE_FINALLY(sp); + } } POP_EXC_BLOCK(); } @@ -1117,37 +1213,39 @@ unwind_jump:; } code_state = new_code_state; *code_state->sp = res; - goto run_code_state; + goto run_code_state_from_return; } #endif + FRAME_LEAVE(); return MP_VM_RETURN_NORMAL; - ENTRY(MP_BC_RAISE_VARARGS): { + ENTRY(MP_BC_RAISE_LAST): { MARK_EXC_IP_SELECTIVE(); - mp_uint_t unum = *ip; - mp_obj_t obj; - if (unum == 2) { - mp_warning(NULL, "exception chaining not supported"); - // ignore (pop) "from" argument - sp--; - } - if (unum == 0) { - // search for the inner-most previous exception, to reraise it - obj = MP_OBJ_NULL; - for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; e--) { - if (e->prev_exc != NULL) { - obj = MP_OBJ_FROM_PTR(e->prev_exc); - break; - } - } - if (obj == MP_OBJ_NULL) { - obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, "no active exception to reraise"); - RAISE(obj); + // search for the inner-most previous exception, to reraise it + mp_obj_t obj = MP_OBJ_NULL; + for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; --e) { + if (e->prev_exc != NULL) { + obj = MP_OBJ_FROM_PTR(e->prev_exc); + break; } - } else { - obj = TOP(); } - obj = mp_make_raise_obj(obj); + if (obj == MP_OBJ_NULL) { + obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, "no active exception to reraise"); + } + RAISE(obj); + } + + ENTRY(MP_BC_RAISE_OBJ): { + MARK_EXC_IP_SELECTIVE(); + mp_obj_t obj = mp_make_raise_obj(TOP()); + RAISE(obj); + } + + ENTRY(MP_BC_RAISE_FROM): { + MARK_EXC_IP_SELECTIVE(); + mp_warning(NULL, "exception chaining not supported"); + sp--; // ignore (pop) "from" argument + mp_obj_t obj = mp_make_raise_obj(TOP()); RAISE(obj); } @@ -1156,7 +1254,8 @@ unwind_jump:; nlr_pop(); code_state->ip = ip; code_state->sp = sp; - code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, 0); + code_state->exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_FROM_PTR(exc_stack, exc_sp); + FRAME_LEAVE(); return MP_VM_RETURN_YIELD; ENTRY(MP_BC_YIELD_FROM): { @@ -1198,21 +1297,15 @@ unwind_jump:; DISPATCH(); } else { assert(ret_kind == MP_VM_RETURN_EXCEPTION); + assert(!EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))); // Pop exhausted gen sp--; - if (EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { - PUSH(mp_obj_exception_get_value(ret_value)); - // If we injected GeneratorExit downstream, then even - // if it was swallowed, we re-raise GeneratorExit - GENERATOR_EXIT_IF_NEEDED(t_exc); - DISPATCH(); - } else { - RAISE(ret_value); - } + RAISE(ret_value); } } ENTRY(MP_BC_IMPORT_NAME): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t obj = POP(); @@ -1221,6 +1314,7 @@ unwind_jump:; } ENTRY(MP_BC_IMPORT_FROM): { + FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t obj = mp_import_from(TOP(), qst); @@ -1235,7 +1329,7 @@ unwind_jump:; #if MICROPY_OPT_COMPUTED_GOTO ENTRY(MP_BC_LOAD_CONST_SMALL_INT_MULTI): - PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16)); + PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS)); DISPATCH(); ENTRY(MP_BC_LOAD_FAST_MULTI): @@ -1263,19 +1357,19 @@ unwind_jump:; MARK_EXC_IP_SELECTIVE(); #else ENTRY_DEFAULT: - if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) { - PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16)); + if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + MP_BC_LOAD_CONST_SMALL_INT_MULTI_NUM) { + PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS)); DISPATCH(); - } else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) { + } else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + MP_BC_LOAD_FAST_MULTI_NUM) { obj_shared = fastn[MP_BC_LOAD_FAST_MULTI - (mp_int_t)ip[-1]]; goto load_check; - } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) { + } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + MP_BC_STORE_FAST_MULTI_NUM) { fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP(); DISPATCH(); - } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) { + } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_BC_UNARY_OP_MULTI_NUM) { SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP())); DISPATCH(); - } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) { + } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BC_BINARY_OP_MULTI_NUM) { mp_obj_t rhs = POP(); mp_obj_t lhs = TOP(); SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs)); @@ -1283,9 +1377,11 @@ unwind_jump:; } else #endif { - mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented"); + + mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "opcode"); nlr_pop(); code_state->state[0] = obj; + FRAME_LEAVE(); return MP_VM_RETURN_EXCEPTION; } @@ -1376,24 +1472,32 @@ unwind_jump:; } } + #if MICROPY_PY_SYS_SETTRACE + // Exceptions are traced here + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_Exception))) { + TRACE_TICK(code_state->ip, code_state->sp, true /* yes, it's an exception */); + } + #endif + #if MICROPY_STACKLESS unwind_loop: #endif - // set file and line number that the exception occurred at - // TODO: don't set traceback for exceptions re-raised by END_FINALLY. - // But consider how to handle nested exceptions. - if (nlr.ret_val != &mp_const_GeneratorExit_obj) { + // Set traceback info (file and line number) where the exception occurred, but not for: + // - constant GeneratorExit object, because it's const + // - exceptions re-raised by END_FINALLY + // - exceptions re-raised explicitly by "raise" + if (nlr.ret_val != &mp_const_GeneratorExit_obj + && *code_state->ip != MP_BC_END_FINALLY + && *code_state->ip != MP_BC_RAISE_LAST) { const byte *ip = code_state->fun_bc->bytecode; - ip = mp_decode_uint_skip(ip); // skip n_state - ip = mp_decode_uint_skip(ip); // skip n_exc_stack - ip++; // skip scope_params - ip++; // skip n_pos_args - ip++; // skip n_kwonly_args - ip++; // skip n_def_pos_args - size_t bc = code_state->ip - ip; - size_t code_info_size = mp_decode_uint_value(ip); - ip = mp_decode_uint_skip(ip); // skip code_info_size - bc -= code_info_size; + MP_BC_PRELUDE_SIG_DECODE(ip); + MP_BC_PRELUDE_SIZE_DECODE(ip); + const byte *bytecode_start = ip + n_info + n_cell; + #if !MICROPY_PERSISTENT_CODE + // so bytecode is aligned + bytecode_start = MP_ALIGN(bytecode_start, sizeof(mp_uint_t)); + #endif + size_t bc = code_state->ip - bytecode_start; #if MICROPY_PERSISTENT_CODE qstr block_name = ip[0] | (ip[1] << 8); qstr source_file = ip[2] | (ip[3] << 8); @@ -1404,29 +1508,7 @@ unwind_jump:; qstr source_file = mp_decode_uint_value(ip); ip = mp_decode_uint_skip(ip); #endif - size_t source_line = 1; - size_t c; - while ((c = *ip)) { - size_t b, l; - if ((c & 0x80) == 0) { - // 0b0LLBBBBB encoding - b = c & 0x1f; - l = c >> 5; - ip += 1; - } else { - // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) - b = c & 0xf; - l = ((c << 4) & 0x700) | ip[1]; - ip += 2; - } - if (bc >= b) { - bc -= b; - source_line += l; - } else { - // found source line corresponding to bytecode offset - break; - } - } + size_t source_line = mp_bytecode_get_source_line(ip, bc); mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(nlr.ret_val), source_file, source_line, block_name); } @@ -1465,11 +1547,11 @@ unwind_jump:; mp_nonlocal_free(code_state, sizeof(mp_code_state_t)); } code_state = new_code_state; - size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); + size_t n_state = code_state->n_state; fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); // variables that are visible to the exception handler (declared volatile) - exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack + exc_sp = MP_CODE_STATE_EXC_SP_IDX_TO_PTR(exc_stack, code_state->exc_sp_idx); // stack grows up, exc_sp points to top of stack goto unwind_loop; #endif @@ -1477,6 +1559,7 @@ unwind_jump:; // propagate exception to higher level // Note: ip and sp don't have usable values at this point code_state->state[0] = MP_OBJ_FROM_PTR(nlr.ret_val); // put exception here because sp is invalid + FRAME_LEAVE(); return MP_VM_RETURN_EXCEPTION; } } diff --git a/micropython/py/vmentrytable.h b/micropython/py/vmentrytable.h index 641c8ee..7f55a48 100644 --- a/micropython/py/vmentrytable.h +++ b/micropython/py/vmentrytable.h @@ -99,17 +99,19 @@ static const void *const entry_table[256] = { [MP_BC_CALL_METHOD] = &&entry_MP_BC_CALL_METHOD, [MP_BC_CALL_METHOD_VAR_KW] = &&entry_MP_BC_CALL_METHOD_VAR_KW, [MP_BC_RETURN_VALUE] = &&entry_MP_BC_RETURN_VALUE, - [MP_BC_RAISE_VARARGS] = &&entry_MP_BC_RAISE_VARARGS, + [MP_BC_RAISE_LAST] = &&entry_MP_BC_RAISE_LAST, + [MP_BC_RAISE_OBJ] = &&entry_MP_BC_RAISE_OBJ, + [MP_BC_RAISE_FROM] = &&entry_MP_BC_RAISE_FROM, [MP_BC_YIELD_VALUE] = &&entry_MP_BC_YIELD_VALUE, [MP_BC_YIELD_FROM] = &&entry_MP_BC_YIELD_FROM, [MP_BC_IMPORT_NAME] = &&entry_MP_BC_IMPORT_NAME, [MP_BC_IMPORT_FROM] = &&entry_MP_BC_IMPORT_FROM, [MP_BC_IMPORT_STAR] = &&entry_MP_BC_IMPORT_STAR, - [MP_BC_LOAD_CONST_SMALL_INT_MULTI ... MP_BC_LOAD_CONST_SMALL_INT_MULTI + 63] = &&entry_MP_BC_LOAD_CONST_SMALL_INT_MULTI, - [MP_BC_LOAD_FAST_MULTI ... MP_BC_LOAD_FAST_MULTI + 15] = &&entry_MP_BC_LOAD_FAST_MULTI, - [MP_BC_STORE_FAST_MULTI ... MP_BC_STORE_FAST_MULTI + 15] = &&entry_MP_BC_STORE_FAST_MULTI, - [MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE - 1] = &&entry_MP_BC_UNARY_OP_MULTI, - [MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE - 1] = &&entry_MP_BC_BINARY_OP_MULTI, + [MP_BC_LOAD_CONST_SMALL_INT_MULTI ... MP_BC_LOAD_CONST_SMALL_INT_MULTI + MP_BC_LOAD_CONST_SMALL_INT_MULTI_NUM - 1] = &&entry_MP_BC_LOAD_CONST_SMALL_INT_MULTI, + [MP_BC_LOAD_FAST_MULTI ... MP_BC_LOAD_FAST_MULTI + MP_BC_LOAD_FAST_MULTI_NUM - 1] = &&entry_MP_BC_LOAD_FAST_MULTI, + [MP_BC_STORE_FAST_MULTI ... MP_BC_STORE_FAST_MULTI + MP_BC_STORE_FAST_MULTI_NUM - 1] = &&entry_MP_BC_STORE_FAST_MULTI, + [MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + MP_BC_UNARY_OP_MULTI_NUM - 1] = &&entry_MP_BC_UNARY_OP_MULTI, + [MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + MP_BC_BINARY_OP_MULTI_NUM - 1] = &&entry_MP_BC_BINARY_OP_MULTI, }; #if __clang__ diff --git a/micropython/tools/make-frozen.py b/micropython/tools/make-frozen.py index 1051b52..8809fd0 100755 --- a/micropython/tools/make-frozen.py +++ b/micropython/tools/make-frozen.py @@ -27,14 +27,15 @@ def module_name(f): modules = [] -root = sys.argv[1].rstrip("/") -root_len = len(root) +if len(sys.argv) > 1: + root = sys.argv[1].rstrip("/") + root_len = len(root) -for dirpath, dirnames, filenames in os.walk(root): - for f in filenames: - fullpath = dirpath + "/" + f - st = os.stat(fullpath) - modules.append((fullpath[root_len + 1:], st)) + for dirpath, dirnames, filenames in os.walk(root): + for f in filenames: + fullpath = dirpath + "/" + f + st = os.stat(fullpath) + modules.append((fullpath[root_len + 1:], st)) print("#include ") print("const char mp_frozen_str_names[] = {") diff --git a/micropython/tools/makemanifest.py b/micropython/tools/makemanifest.py new file mode 100644 index 0000000..90cec2b --- /dev/null +++ b/micropython/tools/makemanifest.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python3 +# +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2019 Damien P. George +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +from __future__ import print_function +import sys +import os +import subprocess + + +########################################################################### +# Public functions to be used in the manifest + +def include(manifest): + """Include another manifest. + + The manifest argument can be a string (filename) or an iterable of + strings. + + Relative paths are resolved with respect to the current manifest file. + """ + + if not isinstance(manifest, str): + for m in manifest: + include(m) + else: + manifest = convert_path(manifest) + with open(manifest) as f: + # Make paths relative to this manifest file while processing it. + # Applies to includes and input files. + prev_cwd = os.getcwd() + os.chdir(os.path.dirname(manifest)) + exec(f.read()) + os.chdir(prev_cwd) + +def freeze(path, script=None, opt=0): + """Freeze the input, automatically determining its type. A .py script + will be compiled to a .mpy first then frozen, and a .mpy file will be + frozen directly. + + `path` must be a directory, which is the base directory to search for + files from. When importing the resulting frozen modules, the name of + the module will start after `path`, ie `path` is excluded from the + module name. + + If `path` is relative, it is resolved to the current manifest.py. + Use $(MPY_DIR), $(MPY_LIB_DIR), $(PORT_DIR), $(BOARD_DIR) if you need + to access specific paths. + + If `script` is None all files in `path` will be frozen. + + If `script` is an iterable then freeze() is called on all items of the + iterable (with the same `path` and `opt` passed through). + + If `script` is a string then it specifies the filename to freeze, and + can include extra directories before the file. The file will be + searched for in `path`. + + `opt` is the optimisation level to pass to mpy-cross when compiling .py + to .mpy. + """ + + freeze_internal(KIND_AUTO, path, script, opt) + +def freeze_as_str(path): + """Freeze the given `path` and all .py scripts within it as a string, + which will be compiled upon import. + """ + + freeze_internal(KIND_AS_STR, path, None, 0) + +def freeze_as_mpy(path, script=None, opt=0): + """Freeze the input (see above) by first compiling the .py scripts to + .mpy files, then freezing the resulting .mpy files. + """ + + freeze_internal(KIND_AS_MPY, path, script, opt) + +def freeze_mpy(path, script=None, opt=0): + """Freeze the input (see above), which must be .mpy files that are + frozen directly. + """ + + freeze_internal(KIND_MPY, path, script, opt) + + +########################################################################### +# Internal implementation + +KIND_AUTO = 0 +KIND_AS_STR = 1 +KIND_AS_MPY = 2 +KIND_MPY = 3 + +VARS = {} + +manifest_list = [] + +class FreezeError(Exception): + pass + +def system(cmd): + try: + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + return 0, output + except subprocess.CalledProcessError as er: + return -1, er.output + +def convert_path(path): + # Perform variable substituion. + for name, value in VARS.items(): + path = path.replace('$({})'.format(name), value) + # Convert to absolute path (so that future operations don't rely on + # still being chdir'ed). + return os.path.abspath(path) + +def get_timestamp(path, default=None): + try: + stat = os.stat(path) + return stat.st_mtime + except OSError: + if default is None: + raise FreezeError('cannot stat {}'.format(path)) + return default + +def get_timestamp_newest(path): + ts_newest = 0 + for dirpath, dirnames, filenames in os.walk(path, followlinks=True): + for f in filenames: + ts_newest = max(ts_newest, get_timestamp(os.path.join(dirpath, f))) + return ts_newest + +def mkdir(path): + cur_path = '' + for p in path.split('/')[:-1]: + cur_path += p + '/' + try: + os.mkdir(cur_path) + except OSError as er: + if er.args[0] == 17: # file exists + pass + else: + raise er + +def freeze_internal(kind, path, script, opt): + path = convert_path(path) + if script is None and kind == KIND_AS_STR: + if any(f[0] == KIND_AS_STR for f in manifest_list): + raise FreezeError('can only freeze one str directory') + manifest_list.append((KIND_AS_STR, path, script, opt)) + elif script is None: + for dirpath, dirnames, filenames in os.walk(path, followlinks=True): + for f in filenames: + freeze_internal(kind, path, (dirpath + '/' + f)[len(path) + 1:], opt) + elif not isinstance(script, str): + for s in script: + freeze_internal(kind, path, s, opt) + else: + extension_kind = {KIND_AS_MPY: '.py', KIND_MPY: '.mpy'} + if kind == KIND_AUTO: + for k, ext in extension_kind.items(): + if script.endswith(ext): + kind = k + break + else: + print('warn: unsupported file type, skipped freeze: {}'.format(script)) + return + wanted_extension = extension_kind[kind] + if not script.endswith(wanted_extension): + raise FreezeError('expecting a {} file, got {}'.format(wanted_extension, script)) + manifest_list.append((kind, path, script, opt)) + +def main(): + # Parse arguments + import argparse + cmd_parser = argparse.ArgumentParser(description='A tool to generate frozen content in MicroPython firmware images.') + cmd_parser.add_argument('-o', '--output', help='output path') + cmd_parser.add_argument('-b', '--build-dir', help='output path') + cmd_parser.add_argument('-f', '--mpy-cross-flags', default='', help='flags to pass to mpy-cross') + cmd_parser.add_argument('-v', '--var', action='append', help='variables to substitute') + cmd_parser.add_argument('files', nargs='+', help='input manifest list') + args = cmd_parser.parse_args() + + # Extract variables for substitution. + for var in args.var: + name, value = var.split('=', 1) + if os.path.exists(value): + value = os.path.abspath(value) + VARS[name] = value + + if 'MPY_DIR' not in VARS or 'PORT_DIR' not in VARS: + print('MPY_DIR and PORT_DIR variables must be specified') + sys.exit(1) + + # Get paths to tools + MAKE_FROZEN = VARS['MPY_DIR'] + '/tools/make-frozen.py' + MPY_CROSS = VARS['MPY_DIR'] + '/mpy-cross/mpy-cross' + MPY_TOOL = VARS['MPY_DIR'] + '/tools/mpy-tool.py' + + # Ensure mpy-cross is built + if not os.path.exists(MPY_CROSS): + print('mpy-cross not found at {}, please build it first'.format(MPY_CROSS)) + sys.exit(1) + + # Include top-level inputs, to generate the manifest + for input_manifest in args.files: + try: + if input_manifest.endswith('.py'): + include(input_manifest) + else: + exec(input_manifest) + except FreezeError as er: + print('freeze error executing "{}": {}'.format(input_manifest, er.args[0])) + sys.exit(1) + + # Process the manifest + str_paths = [] + mpy_files = [] + ts_newest = 0 + for kind, path, script, opt in manifest_list: + if kind == KIND_AS_STR: + str_paths.append(path) + ts_outfile = get_timestamp_newest(path) + elif kind == KIND_AS_MPY: + infile = '{}/{}'.format(path, script) + outfile = '{}/frozen_mpy/{}.mpy'.format(args.build_dir, script[:-3]) + ts_infile = get_timestamp(infile) + ts_outfile = get_timestamp(outfile, 0) + if ts_infile >= ts_outfile: + print('MPY', script) + mkdir(outfile) + res, out = system([MPY_CROSS] + args.mpy_cross_flags.split() + ['-o', outfile, '-s', script, '-O{}'.format(opt), infile]) + if res != 0: + print('error compiling {}: {}'.format(infile, out)) + raise SystemExit(1) + ts_outfile = get_timestamp(outfile) + mpy_files.append(outfile) + else: + assert kind == KIND_MPY + infile = '{}/{}'.format(path, script) + mpy_files.append(infile) + ts_outfile = get_timestamp(infile) + ts_newest = max(ts_newest, ts_outfile) + + # Check if output file needs generating + if ts_newest < get_timestamp(args.output, 0): + # No files are newer than output file so it does not need updating + return + + # Freeze paths as strings + res, output_str = system([sys.executable, MAKE_FROZEN] + str_paths) + if res != 0: + print('error freezing strings {}: {}'.format(str_paths, output_str)) + sys.exit(1) + + # Freeze .mpy files + res, output_mpy = system([sys.executable, MPY_TOOL, '-f', '-q', args.build_dir + '/genhdr/qstrdefs.preprocessed.h'] + mpy_files) + if res != 0: + print('error freezing mpy {}: {}'.format(mpy_files, output_mpy)) + sys.exit(1) + + # Generate output + print('GEN', args.output) + mkdir(args.output) + with open(args.output, 'wb') as f: + f.write(b'//\n// Content for MICROPY_MODULE_FROZEN_STR\n//\n') + f.write(output_str) + f.write(b'//\n// Content for MICROPY_MODULE_FROZEN_MPY\n//\n') + f.write(output_mpy) + +if __name__ == '__main__': + main() diff --git a/micropython/tools/mpy-tool.py b/micropython/tools/mpy-tool.py index a96934b..81a390b 100755 --- a/micropython/tools/mpy-tool.py +++ b/micropython/tools/mpy-tool.py @@ -4,7 +4,7 @@ # # The MIT License (MIT) # -# Copyright (c) 2016 Damien P. George +# Copyright (c) 2016-2019 Damien P. George # Copyright (c) 2019 LoBo (https://github.com/loboris) # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -58,7 +58,7 @@ def __str__(self): return 'error while freezing %s: %s' % (self.rawcode.source_file, self.msg) class Config: - MPY_VERSION = 4 + MPY_VERSION = 5 MICROPY_LONGINT_IMPL_NONE = 0 MICROPY_LONGINT_IMPL_LONGLONG = 1 MICROPY_LONGINT_IMPL_MPZ = 2 @@ -71,7 +71,7 @@ def __init__(self, str): self.qstr_id = 'MP_QSTR_' + self.qstr_esc # Initialise global list of qstrs with static qstrs -global_qstrs = [None] # MP_QSTR_NULL should never be referenced +global_qstrs = [None] # MP_QSTRnull should never be referenced for n in qstrutil.static_qstr_list: global_qstrs.append(QStrType(n)) @@ -103,110 +103,27 @@ def access(self, idx): MP_NATIVE_ARCH_ARMV7EMSP = 7 MP_NATIVE_ARCH_ARMV7EMDP = 8 MP_NATIVE_ARCH_XTENSA = 9 +MP_NATIVE_ARCH_XTENSAWIN = 10 -MP_OPCODE_BYTE = 0 -MP_OPCODE_QSTR = 1 -MP_OPCODE_VAR_UINT = 2 -MP_OPCODE_OFFSET = 3 +MP_BC_MASK_EXTRA_BYTE = 0x9e + +MP_BC_FORMAT_BYTE = 0 +MP_BC_FORMAT_QSTR = 1 +MP_BC_FORMAT_VAR_UINT = 2 +MP_BC_FORMAT_OFFSET = 3 -# extra bytes: -MP_BC_MAKE_CLOSURE = 0x62 -MP_BC_MAKE_CLOSURE_DEFARGS = 0x63 -MP_BC_RAISE_VARARGS = 0x5c # extra byte if caching enabled: -MP_BC_LOAD_NAME = 0x1b -MP_BC_LOAD_GLOBAL = 0x1c -MP_BC_LOAD_ATTR = 0x1d -MP_BC_STORE_ATTR = 0x26 - -def make_opcode_format(): - def OC4(a, b, c, d): - return a | (b << 2) | (c << 4) | (d << 6) - U = 0 - B = 0 - Q = 1 - V = 2 - O = 3 - return bytes_cons(( - # this table is taken verbatim from py/bc.c - OC4(U, U, U, U), # 0x00-0x03 - OC4(U, U, U, U), # 0x04-0x07 - OC4(U, U, U, U), # 0x08-0x0b - OC4(U, U, U, U), # 0x0c-0x0f - OC4(B, B, B, U), # 0x10-0x13 - OC4(V, U, Q, V), # 0x14-0x17 - OC4(B, V, V, Q), # 0x18-0x1b - OC4(Q, Q, Q, Q), # 0x1c-0x1f - OC4(B, B, V, V), # 0x20-0x23 - OC4(Q, Q, Q, B), # 0x24-0x27 - OC4(V, V, Q, Q), # 0x28-0x2b - OC4(U, U, U, U), # 0x2c-0x2f - OC4(B, B, B, B), # 0x30-0x33 - OC4(B, O, O, O), # 0x34-0x37 - OC4(O, O, U, U), # 0x38-0x3b - OC4(U, O, B, O), # 0x3c-0x3f - OC4(O, B, B, O), # 0x40-0x43 - OC4(O, U, O, B), # 0x44-0x47 - OC4(U, U, U, U), # 0x48-0x4b - OC4(U, U, U, U), # 0x4c-0x4f - OC4(V, V, U, V), # 0x50-0x53 - OC4(B, U, V, V), # 0x54-0x57 - OC4(V, V, V, B), # 0x58-0x5b - OC4(B, B, B, U), # 0x5c-0x5f - OC4(V, V, V, V), # 0x60-0x63 - OC4(V, V, V, V), # 0x64-0x67 - OC4(Q, Q, B, U), # 0x68-0x6b - OC4(U, U, U, U), # 0x6c-0x6f - - OC4(B, B, B, B), # 0x70-0x73 - OC4(B, B, B, B), # 0x74-0x77 - OC4(B, B, B, B), # 0x78-0x7b - OC4(B, B, B, B), # 0x7c-0x7f - OC4(B, B, B, B), # 0x80-0x83 - OC4(B, B, B, B), # 0x84-0x87 - OC4(B, B, B, B), # 0x88-0x8b - OC4(B, B, B, B), # 0x8c-0x8f - OC4(B, B, B, B), # 0x90-0x93 - OC4(B, B, B, B), # 0x94-0x97 - OC4(B, B, B, B), # 0x98-0x9b - OC4(B, B, B, B), # 0x9c-0x9f - OC4(B, B, B, B), # 0xa0-0xa3 - OC4(B, B, B, B), # 0xa4-0xa7 - OC4(B, B, B, B), # 0xa8-0xab - OC4(B, B, B, B), # 0xac-0xaf - - OC4(B, B, B, B), # 0xb0-0xb3 - OC4(B, B, B, B), # 0xb4-0xb7 - OC4(B, B, B, B), # 0xb8-0xbb - OC4(B, B, B, B), # 0xbc-0xbf - - OC4(B, B, B, B), # 0xc0-0xc3 - OC4(B, B, B, B), # 0xc4-0xc7 - OC4(B, B, B, B), # 0xc8-0xcb - OC4(B, B, B, B), # 0xcc-0xcf - - OC4(B, B, B, B), # 0xd0-0xd3 - OC4(U, U, U, B), # 0xd4-0xd7 - OC4(B, B, B, B), # 0xd8-0xdb - OC4(B, B, B, B), # 0xdc-0xdf - - OC4(B, B, B, B), # 0xe0-0xe3 - OC4(B, B, B, B), # 0xe4-0xe7 - OC4(B, B, B, B), # 0xe8-0xeb - OC4(B, B, B, B), # 0xec-0xef - - OC4(B, B, B, B), # 0xf0-0xf3 - OC4(B, B, B, B), # 0xf4-0xf7 - OC4(U, U, U, U), # 0xf8-0xfb - OC4(U, U, U, U), # 0xfc-0xff - )) +MP_BC_LOAD_NAME = 0x11 +MP_BC_LOAD_GLOBAL = 0x12 +MP_BC_LOAD_ATTR = 0x13 +MP_BC_STORE_ATTR = 0x18 # this function mirrors that in py/bc.c -def mp_opcode_format(bytecode, ip, count_var_uint, opcode_format=make_opcode_format()): +def mp_opcode_format(bytecode, ip, count_var_uint): opcode = bytecode[ip] ip_start = ip - f = (opcode_format[opcode >> 2] >> (2 * (opcode & 3))) & 3 - if f == MP_OPCODE_QSTR: + f = ((0x000003a4 >> (2 * ((opcode) >> 4))) & 3) + if f == MP_BC_FORMAT_QSTR: if config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE: if (opcode == MP_BC_LOAD_NAME or opcode == MP_BC_LOAD_GLOBAL @@ -215,47 +132,70 @@ def mp_opcode_format(bytecode, ip, count_var_uint, opcode_format=make_opcode_for ip += 1 ip += 3 else: - extra_byte = ( - opcode == MP_BC_RAISE_VARARGS - or opcode == MP_BC_MAKE_CLOSURE - or opcode == MP_BC_MAKE_CLOSURE_DEFARGS - ) + extra_byte = (opcode & MP_BC_MASK_EXTRA_BYTE) == 0 ip += 1 - if f == MP_OPCODE_VAR_UINT: + if f == MP_BC_FORMAT_VAR_UINT: if count_var_uint: while bytecode[ip] & 0x80 != 0: ip += 1 ip += 1 - elif f == MP_OPCODE_OFFSET: + elif f == MP_BC_FORMAT_OFFSET: ip += 2 ip += extra_byte return f, ip - ip_start -def decode_uint(bytecode, ip): - unum = 0 +def read_prelude_sig(read_byte): + z = read_byte() + # xSSSSEAA + S = (z >> 3) & 0xf + E = (z >> 2) & 0x1 + F = 0 + A = z & 0x3 + K = 0 + D = 0 + n = 0 + while z & 0x80: + z = read_byte() + # xFSSKAED + S |= (z & 0x30) << (2 * n) + E |= (z & 0x02) << n + F |= ((z & 0x40) >> 6) << n + A |= (z & 0x4) << n + K |= ((z & 0x08) >> 3) << n + D |= (z & 0x1) << n + n += 1 + S += 1 + return S, E, F, A, K, D + +def read_prelude_size(read_byte): + I = 0 + C = 0 + n = 0 while True: - val = bytecode[ip] - ip += 1 - unum = (unum << 7) | (val & 0x7f) - if not (val & 0x80): + z = read_byte() + # xIIIIIIC + I |= ((z & 0x7e) >> 1) << (6 * n) + C |= (z & 1) << n + if not (z & 0x80): break - return ip, unum + n += 1 + return I, C def extract_prelude(bytecode, ip): - ip, n_state = decode_uint(bytecode, ip) - ip, n_exc_stack = decode_uint(bytecode, ip) - scope_flags = bytecode[ip]; ip += 1 - n_pos_args = bytecode[ip]; ip += 1 - n_kwonly_args = bytecode[ip]; ip += 1 - n_def_pos_args = bytecode[ip]; ip += 1 - ip2, code_info_size = decode_uint(bytecode, ip) - ip += code_info_size - while bytecode[ip] != 0xff: - ip += 1 - ip += 1 + def local_read_byte(): + b = bytecode[ip_ref[0]] + ip_ref[0] += 1 + return b + ip_ref = [ip] # to close over ip in Python 2 and 3 + n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args = read_prelude_sig(local_read_byte) + n_info, n_cell = read_prelude_size(local_read_byte) + ip = ip_ref[0] + + ip2 = ip + ip = ip2 + n_info + n_cell # ip now points to first opcode # ip2 points to simple_name qstr - return ip, ip2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args, code_info_size) + return ip, ip2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args) class MPFunTable: pass @@ -375,7 +315,7 @@ def freeze_constants(self): print(' MP_ROM_QSTR(%s),' % global_qstrs[qst].qstr_id) for i in range(len(self.objs)): if self.objs[i] is MPFunTable: - print(' mp_fun_table,') + print(' &mp_fun_table,') elif type(self.objs[i]) is float: print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') print(' MP_ROM_PTR(&const_obj_%s_%u),' % (self.escaped_name, i)) @@ -418,13 +358,29 @@ def freeze_module(self, qstr_links=(), type_sig=0): print(' .fun_data_len = %u,' % len(self.bytecode)) print(' .n_obj = %u,' % len(self.objs)) print(' .n_raw_code = %u,' % len(self.raw_codes)) - print(' #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM') + if self.code_kind == MP_CODE_BYTECODE: + print(' #if MICROPY_PY_SYS_SETTRACE') + print(' .prelude = {') + print(' .n_state = %u,' % self.prelude[0]) + print(' .n_exc_stack = %u,' % self.prelude[1]) + print(' .scope_flags = %u,' % self.prelude[2]) + print(' .n_pos_args = %u,' % self.prelude[3]) + print(' .n_kwonly_args = %u,' % self.prelude[4]) + print(' .n_def_pos_args = %u,' % self.prelude[5]) + print(' .qstr_block_name = %s,' % self.simple_name.qstr_id) + print(' .qstr_source_file = %s,' % self.source_file.qstr_id) + print(' .line_info = fun_data_%s + %u,' % (self.escaped_name, 0)) # TODO + print(' .opcodes = fun_data_%s + %u,' % (self.escaped_name, self.ip)) + print(' },') + print(' .line_of_definition = %u,' % 0) # TODO + print(' #endif') + print(' #if MICROPY_EMIT_MACHINE_CODE') print(' .prelude_offset = %u,' % self.prelude_offset) print(' .n_qstr = %u,' % len(qstr_links)) print(' .qstr_link = NULL,') # TODO print(' #endif') print(' #endif') - print(' #if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM') + print(' #if MICROPY_EMIT_MACHINE_CODE') print(' .type_sig = %u,' % type_sig) print(' #endif') print('};') @@ -474,11 +430,22 @@ def __init__(self, code_kind, fun_data, prelude_offset, prelude, qstr_links, qst self.prelude = prelude self.qstr_links = qstr_links self.type_sig = type_sig - if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64): + if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64, + MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN): self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",@progbits # ")))' else: self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",%progbits @ ")))' + # Allow single-byte alignment by default for x86/x64. + # ARM needs word alignment, ARM Thumb needs halfword, due to instruction size. + # Xtensa needs word alignment due to the 32-bit constant table embedded in the code. + if config.native_arch in (MP_NATIVE_ARCH_ARMV6, MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN): + # ARMV6 or Xtensa -- four byte align. + self.fun_data_attributes += ' __attribute__ ((aligned (4)))' + elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP: + # ARMVxxM -- two byte align. + self.fun_data_attributes += ' __attribute__ ((aligned (2)))' + def _asm_thumb_rewrite_mov(self, pc, val): print(' (%u & 0xf0) | (%s >> 12),' % (self.bytecode[pc], val), end='') print(' (%u & 0xfb) | (%s >> 9 & 0x04),' % (self.bytecode[pc + 1], val), end='') @@ -487,22 +454,37 @@ def _asm_thumb_rewrite_mov(self, pc, val): def _link_qstr(self, pc, kind, qst): if kind == 0: + # Generic 16-bit link print(' %s & 0xff, %s >> 8,' % (qst, qst)) + return 2 else: - if kind == 2: + # Architecture-specific link + is_obj = kind == 2 + if is_obj: qst = '((uintptr_t)MP_OBJ_NEW_QSTR(%s))' % qst - if config.native_arch in (MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64): - print(' %s & 0xff, %s >> 8, 0, 0,' % (qst, qst)) + if config.native_arch in ( + MP_NATIVE_ARCH_X86, MP_NATIVE_ARCH_X64, + MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN + ): + print(' %s & 0xff, (%s >> 8) & 0xff, (%s >> 16) & 0xff, %s >> 24,' % (qst, qst, qst, qst)) + return 4 elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP: if is_obj: - self._asm_thumb_rewrite_mov(i, qst) - self._asm_thumb_rewrite_mov(i + 4, '(%s >> 16)' % qst) + # qstr object, movw and movt + self._asm_thumb_rewrite_mov(pc, qst) + self._asm_thumb_rewrite_mov(pc + 4, '(%s >> 16)' % qst) + return 8 else: - self._asm_thumb_rewrite_mov(i, qst) + # qstr number, movw instruction + self._asm_thumb_rewrite_mov(pc, qst) + return 4 else: assert 0 def freeze(self, parent_name): + if self.prelude[2] & ~0x0f: + raise FreezeError('unable to freeze code with relocations') + self.freeze_children(parent_name) # generate native code data @@ -526,8 +508,7 @@ def freeze(self, parent_name): # link qstr qi_off, qi_kind, qi_val = self.qstr_links[qi] qst = global_qstrs[qi_val].qstr_id - self._link_qstr(i, qi_kind, qst) - i += 4 + i += self._link_qstr(i, qi_kind, qst) qi += 1 else: # copy machine code (max 16 bytes) @@ -619,21 +600,14 @@ def read_obj(f): else: assert 0 -def read_prelude(f, bytecode): - n_state = read_uint(f, bytecode) - n_exc_stack = read_uint(f, bytecode) - scope_flags = read_byte(f, bytecode) - n_pos_args = read_byte(f, bytecode) - n_kwonly_args = read_byte(f, bytecode) - n_def_pos_args = read_byte(f, bytecode) - l1 = bytecode.idx - code_info_size = read_uint(f, bytecode) - l2 = bytecode.idx - for _ in range(code_info_size - (l2 - l1)): +def read_prelude(f, bytecode, qstr_win): + n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args = read_prelude_sig(lambda: read_byte(f, bytecode)) + n_info, n_cell = read_prelude_size(lambda: read_byte(f, bytecode)) + read_qstr_and_pack(f, bytecode, qstr_win) # simple_name + read_qstr_and_pack(f, bytecode, qstr_win) # source_file + for _ in range(n_info - 4 + n_cell): read_byte(f, bytecode) - while read_byte(f, bytecode) != 255: - pass - return l2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args, code_info_size) + return n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args def read_qstr_and_pack(f, bytecode, qstr_win): qst = read_qstr(f, qstr_win) @@ -645,10 +619,10 @@ def read_bytecode(file, bytecode, qstr_win): op = read_byte(file, bytecode) f, sz = mp_opcode_format(bytecode.buf, bytecode.idx - 1, False) sz -= 1 - if f == MP_OPCODE_QSTR: + if f == MP_BC_FORMAT_QSTR: read_qstr_and_pack(file, bytecode, qstr_win) sz -= 2 - elif f == MP_OPCODE_VAR_UINT: + elif f == MP_BC_FORMAT_VAR_UINT: while read_byte(file, bytecode) & 0x80: pass for _ in range(sz): @@ -661,7 +635,7 @@ def read_raw_code(f, qstr_win): fun_data = BytecodeBuffer(fun_data_len) if kind == MP_CODE_BYTECODE: - name_idx, prelude = read_prelude(f, fun_data) + prelude = read_prelude(f, fun_data, qstr_win) read_bytecode(f, fun_data, qstr_win) else: fun_data.buf[:] = f.read(fun_data_len) @@ -671,7 +645,7 @@ def read_raw_code(f, qstr_win): # load qstr link table n_qstr_link = read_uint(f) for _ in range(n_qstr_link): - off = read_uint(f, qstr_win) + off = read_uint(f) qst = read_qstr(f, qstr_win) qstr_links.append((off >> 2, off & 3, qst)) @@ -679,6 +653,9 @@ def read_raw_code(f, qstr_win): if kind == MP_CODE_NATIVE_PY: prelude_offset = read_uint(f) _, name_idx, prelude = extract_prelude(fun_data.buf, prelude_offset) + fun_data.idx = name_idx # rewind to where qstrs are in prelude + read_qstr_and_pack(f, fun_data, qstr_win) # simple_name + read_qstr_and_pack(f, fun_data, qstr_win) # source_file else: prelude_offset = None scope_flags = read_uint(f) @@ -688,11 +665,6 @@ def read_raw_code(f, qstr_win): type_sig = read_uint(f) prelude = (None, None, scope_flags, n_pos_args, 0) - if kind in (MP_CODE_BYTECODE, MP_CODE_NATIVE_PY): - fun_data.idx = name_idx # rewind to where qstrs are in prelude - read_qstr_and_pack(f, fun_data, qstr_win) # simple_name - read_qstr_and_pack(f, fun_data, qstr_win) # source_file - qstrs = [] objs = [] raw_codes = [] @@ -722,10 +694,18 @@ def read_mpy(filename): qw_size = read_uint(f) config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = (feature_byte & 1) != 0 config.MICROPY_PY_BUILTINS_STR_UNICODE = (feature_byte & 2) != 0 - config.native_arch = feature_byte >> 2 + mpy_native_arch = feature_byte >> 2 + if mpy_native_arch != MP_NATIVE_ARCH_NONE: + if config.native_arch == MP_NATIVE_ARCH_NONE: + config.native_arch = mpy_native_arch + elif config.native_arch != mpy_native_arch: + raise Exception('native architecture mismatch') config.mp_small_int_bits = header[3] qstr_win = QStrWindow(qw_size) - return read_raw_code(f, qstr_win) + rc = read_raw_code(f, qstr_win) + rc.mpy_source_file = filename + rc.qstr_win_size = qw_size + return rc def dump_mpy(raw_codes): for rc in raw_codes: @@ -745,6 +725,7 @@ def freeze_mpy(base_qstrs, raw_codes): print('#include "py/objint.h"') print('#include "py/objstr.h"') print('#include "py/emitglue.h"') + print('#include "py/nativeglue.h"') print() print('#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE != %u' % config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) @@ -822,6 +803,55 @@ def freeze_mpy(base_qstrs, raw_codes): print(' &raw_code_%s,' % rc.escaped_name) print('};') +def merge_mpy(raw_codes, output_file): + assert len(raw_codes) <= 31 # so var-uints all fit in 1 byte + merged_mpy = bytearray() + + if len(raw_codes) == 1: + with open(raw_codes[0].mpy_source_file, 'rb') as f: + merged_mpy.extend(f.read()) + else: + header = bytearray(5) + header[0] = ord('M') + header[1] = config.MPY_VERSION + header[2] = (config.native_arch << 2 + | config.MICROPY_PY_BUILTINS_STR_UNICODE << 1 + | config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) + header[3] = config.mp_small_int_bits + header[4] = 32 # qstr_win_size + merged_mpy.extend(header) + + bytecode = bytearray() + bytecode_len = 6 + len(raw_codes) * 4 + 2 + bytecode.append(bytecode_len << 2) # kind and length + bytecode.append(0b00000000) # signature prelude + bytecode.append(0b00001000) # size prelude + bytecode.extend(b'\x00\x01') # MP_QSTR_ + bytecode.extend(b'\x00\x01') # MP_QSTR_ + for idx in range(len(raw_codes)): + bytecode.append(0x32) # MP_BC_MAKE_FUNCTION + bytecode.append(idx) # index raw code + bytecode.extend(b'\x34\x00') # MP_BC_CALL_FUNCTION, 0 args + bytecode.extend(b'\x51\x63') # MP_BC_LOAD_NONE, MP_BC_RETURN_VALUE + + bytecode.append(0) # n_obj + bytecode.append(len(raw_codes)) # n_raw_code + + merged_mpy.extend(bytecode) + + for rc in raw_codes: + with open(rc.mpy_source_file, 'rb') as f: + f.read(4) # skip header + read_uint(f) # skip qstr_win_size + data = f.read() # read rest of mpy file + merged_mpy.extend(data) + + if output_file is None: + sys.stdout.buffer.write(merged_mpy) + else: + with open(output_file, 'wb') as f: + f.write(merged_mpy) + def main(): import argparse cmd_parser = argparse.ArgumentParser(description='A tool to work with MicroPython .mpy files.') @@ -829,12 +859,16 @@ def main(): help='dump contents of files') cmd_parser.add_argument('-f', '--freeze', action='store_true', help='freeze files') + cmd_parser.add_argument('--merge', action='store_true', + help='merge multiple .mpy files into one') cmd_parser.add_argument('-q', '--qstr-header', help='qstr header file to freeze against') cmd_parser.add_argument('-mlongint-impl', choices=['none', 'longlong', 'mpz'], default='mpz', help='long-int implementation used by target (default mpz)') cmd_parser.add_argument('-mmpz-dig-size', metavar='N', type=int, default=16, help='mpz digit size used by target (default 16)') + cmd_parser.add_argument('-o', '--output', default=None, + help='output file') cmd_parser.add_argument('files', nargs='+', help='input .mpy files') args = cmd_parser.parse_args() @@ -846,6 +880,7 @@ def main(): 'mpz':config.MICROPY_LONGINT_IMPL_MPZ, }[args.mlongint_impl] config.MPZ_DIG_SIZE = args.mmpz_dig_size + config.native_arch = MP_NATIVE_ARCH_NONE # set config values for qstrs, and get the existing base set of qstrs if args.qstr_header: @@ -867,6 +902,8 @@ def main(): except FreezeError as er: print(er, file=sys.stderr) sys.exit(1) + elif args.merge: + merged_mpy = merge_mpy(raw_codes, args.output) if __name__ == '__main__': main() diff --git a/micropython/tools/mpy_ld.py b/micropython/tools/mpy_ld.py new file mode 100755 index 0000000..31c3912 --- /dev/null +++ b/micropython/tools/mpy_ld.py @@ -0,0 +1,964 @@ +#!/usr/bin/env python3 +# +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2019 Damien P. George +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +""" +Link .o files to .mpy +""" + +import sys, os, struct, re +from elftools.elf import elffile + +sys.path.append(os.path.dirname(__file__) + '/../py') +import makeqstrdata as qstrutil + +# MicroPython constants +MPY_VERSION = 5 +MP_NATIVE_ARCH_X86 = 1 +MP_NATIVE_ARCH_X64 = 2 +MP_NATIVE_ARCH_ARMV7M = 5 +MP_NATIVE_ARCH_ARMV7EMSP = 7 +MP_NATIVE_ARCH_ARMV7EMDP = 8 +MP_NATIVE_ARCH_XTENSA = 9 +MP_NATIVE_ARCH_XTENSAWIN = 10 +MP_CODE_BYTECODE = 2 +MP_CODE_NATIVE_VIPER = 4 +MP_SCOPE_FLAG_VIPERRELOC = 0x10 +MP_SCOPE_FLAG_VIPERRODATA = 0x20 +MP_SCOPE_FLAG_VIPERBSS = 0x40 +MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = 1 +MICROPY_PY_BUILTINS_STR_UNICODE = 2 +MP_SMALL_INT_BITS = 31 +QSTR_WINDOW_SIZE = 32 + +# ELF constants +R_386_32 = 1 +R_X86_64_64 = 1 +R_XTENSA_32 = 1 +R_386_PC32 = 2 +R_X86_64_PC32 = 2 +R_ARM_ABS32 = 2 +R_386_GOT32 = 3 +R_ARM_REL32 = 3 +R_386_PLT32 = 4 +R_X86_64_PLT32 = 4 +R_XTENSA_PLT = 6 +R_386_GOTOFF = 9 +R_386_GOTPC = 10 +R_ARM_THM_CALL = 10 +R_XTENSA_DIFF32 = 19 +R_XTENSA_SLOT0_OP = 20 +R_ARM_BASE_PREL = 25 # aka R_ARM_GOTPC +R_ARM_GOT_BREL = 26 # aka R_ARM_GOT32 +R_ARM_THM_JUMP24 = 30 +R_X86_64_REX_GOTPCRELX = 42 +R_386_GOT32X = 43 + +################################################################################ +# Architecture configuration + +def asm_jump_x86(entry): + return struct.pack('> 11 == 0 or b_off >> 11 == -1: + # Signed value fits in 12 bits + b0 = 0xe000 | (b_off >> 1 & 0x07ff) + b1 = 0 + else: + # Use large jump + b0 = 0xf000 | (b_off >> 12 & 0x07ff) + b1 = 0xb800 | (b_off >> 1 & 0x7ff) + return struct.pack('> 8) + +class ArchData: + def __init__(self, name, mpy_feature, qstr_entry_size, word_size, arch_got, asm_jump): + self.name = name + self.mpy_feature = mpy_feature + self.qstr_entry_size = qstr_entry_size + self.word_size = word_size + self.arch_got = arch_got + self.asm_jump = asm_jump + self.separate_rodata = name == 'EM_XTENSA' and qstr_entry_size == 4 + +ARCH_DATA = { + 'x86': ArchData( + 'EM_386', + MP_NATIVE_ARCH_X86 << 2 | MICROPY_PY_BUILTINS_STR_UNICODE | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE, + 2, 4, (R_386_PC32, R_386_GOT32, R_386_GOT32X), asm_jump_x86, + ), + 'x64': ArchData( + 'EM_X86_64', + MP_NATIVE_ARCH_X64 << 2 | MICROPY_PY_BUILTINS_STR_UNICODE | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE, + 2, 8, (R_X86_64_REX_GOTPCRELX,), asm_jump_x86, + ), + 'armv7m': ArchData( + 'EM_ARM', + MP_NATIVE_ARCH_ARMV7M << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, + 2, 4, (R_ARM_GOT_BREL,), asm_jump_arm, + ), + 'armv7emsp': ArchData( + 'EM_ARM', + MP_NATIVE_ARCH_ARMV7EMSP << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, + 2, 4, (R_ARM_GOT_BREL,), asm_jump_arm, + ), + 'armv7emdp': ArchData( + 'EM_ARM', + MP_NATIVE_ARCH_ARMV7EMDP << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, + 2, 4, (R_ARM_GOT_BREL,), asm_jump_arm, + ), + 'xtensa': ArchData( + 'EM_XTENSA', + MP_NATIVE_ARCH_XTENSA << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, + 2, 4, (R_XTENSA_32, R_XTENSA_PLT), asm_jump_xtensa, + ), + 'xtensawin': ArchData( + 'EM_XTENSA', + MP_NATIVE_ARCH_XTENSAWIN << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, + 4, 4, (R_XTENSA_32, R_XTENSA_PLT), asm_jump_xtensa, + ), +} + +################################################################################ +# Helper functions + +def align_to(value, align): + return (value + align - 1) & ~(align - 1) + +def unpack_u24le(data, offset): + return data[offset] | data[offset + 1] << 8 | data[offset + 2] << 16 + +def pack_u24le(data, offset, value): + data[offset] = value & 0xff + data[offset + 1] = value >> 8 & 0xff + data[offset + 2] = value >> 16 & 0xff + +def xxd(text): + for i in range(0, len(text), 16): + print('{:08x}:'.format(i), end='') + for j in range(4): + off = i + j * 4 + if off < len(text): + d = int.from_bytes(text[off:off + 4], 'little') + print(' {:08x}'.format(d), end='') + print() + +# Smaller numbers are enabled first +LOG_LEVEL_1 = 1 +LOG_LEVEL_2 = 2 +LOG_LEVEL_3 = 3 +log_level = LOG_LEVEL_1 + +def log(level, msg): + if level <= log_level: + print(msg) + +################################################################################ +# Qstr extraction + +def extract_qstrs(source_files): + def read_qstrs(f): + with open(f) as f: + vals = set() + objs = set() + for line in f: + while line: + m = re.search(r'MP_OBJ_NEW_QSTR\((MP_QSTR_[A-Za-z0-9_]*)\)', line) + if m: + objs.add(m.group(1)) + else: + m = re.search(r'MP_QSTR_[A-Za-z0-9_]*', line) + if m: + vals.add(m.group()) + if m: + s = m.span() + line = line[:s[0]] + line[s[1]:] + else: + line = '' + return vals, objs + + static_qstrs = ['MP_QSTR_' + qstrutil.qstr_escape(q) for q in qstrutil.static_qstr_list] + + qstr_vals = set() + qstr_objs = set() + for f in source_files: + vals, objs = read_qstrs(f) + qstr_vals.update(vals) + qstr_objs.update(objs) + qstr_vals.difference_update(static_qstrs) + + return static_qstrs, qstr_vals, qstr_objs + +################################################################################ +# Linker + +class LinkError(Exception): + pass + +class Section: + def __init__(self, name, data, alignment, filename=None): + self.filename = filename + self.name = name + self.data = data + self.alignment = alignment + self.addr = 0 + self.reloc = [] + + @staticmethod + def from_elfsec(elfsec, filename): + assert elfsec.header.sh_addr == 0 + return Section(elfsec.name, elfsec.data(), elfsec.data_alignment, filename) + +class GOTEntry: + def __init__(self, name, sym, link_addr=0): + self.name = name + self.sym = sym + self.offset = None + self.link_addr = link_addr + + def isexternal(self): + return self.sec_name.startswith('.external') + + def istext(self): + return self.sec_name.startswith('.text') + + def isrodata(self): + return self.sec_name.startswith(('.rodata', '.data.rel.ro')) + + def isbss(self): + return self.sec_name.startswith('.bss') + +class LiteralEntry: + def __init__(self, value, offset): + self.value = value + self.offset = offset + +class LinkEnv: + def __init__(self, arch): + self.arch = ARCH_DATA[arch] + self.sections = [] # list of sections in order of output + self.literal_sections = [] # list of literal sections (xtensa only) + self.known_syms = {} # dict of symbols that are defined + self.unresolved_syms = [] # list of unresolved symbols + self.mpy_relocs = [] # list of relocations needed in the output .mpy file + + def check_arch(self, arch_name): + if arch_name != self.arch.name: + raise LinkError('incompatible arch') + + def print_sections(self): + log(LOG_LEVEL_2, 'sections:') + for sec in self.sections: + log(LOG_LEVEL_2, ' {:08x} {} size={}'.format(sec.addr, sec.name, len(sec.data))) + + def find_addr(self, name): + if name in self.known_syms: + s = self.known_syms[name] + return s.section.addr + s['st_value'] + raise LinkError('unknown symbol: {}'.format(name)) + +def build_got_generic(env): + env.got_entries = {} + for sec in env.sections: + for r in sec.reloc: + s = r.sym + if not (s.entry['st_info']['bind'] == 'STB_GLOBAL' and r['r_info_type'] in env.arch.arch_got): + continue + s_type = s.entry['st_info']['type'] + assert s_type in ('STT_NOTYPE', 'STT_FUNC', 'STT_OBJECT'), s_type + assert s.name + if s.name in env.got_entries: + continue + env.got_entries[s.name] = GOTEntry(s.name, s) + +def build_got_xtensa(env): + env.got_entries = {} + env.lit_entries = {} + env.xt_literals = {} + + # Extract the values from the literal table + for sec in env.literal_sections: + assert len(sec.data) % env.arch.word_size == 0 + + # Look through literal relocations to find any global pointers that should be GOT entries + for r in sec.reloc: + s = r.sym + s_type = s.entry['st_info']['type'] + assert s_type in ('STT_NOTYPE', 'STT_FUNC', 'STT_OBJECT', 'STT_SECTION'), s_type + assert r['r_info_type'] in env.arch.arch_got + assert r['r_offset'] % env.arch.word_size == 0 + # This entry is a global pointer + existing = struct.unpack_from(' {}+{:08x}'.format(g.offset, g.name, g.sec_name, g.link_addr)) + +def populate_lit(env): + log(LOG_LEVEL_2, 'LIT: {:08x}'.format(env.lit_section.addr)) + for lit_entry in env.lit_entries.values(): + value = lit_entry.value + log(LOG_LEVEL_2, ' {:08x} = {:08x}'.format(lit_entry.offset, value)) + o = env.lit_section.addr + lit_entry.offset + env.full_text[o:o + env.arch.word_size] = value.to_bytes(env.arch.word_size, 'little') + +def do_relocation_text(env, text_addr, r): + # Extract relevant info about symbol that's being relocated + s = r.sym + s_bind = s.entry['st_info']['bind'] + s_shndx = s.entry['st_shndx'] + s_type = s.entry['st_info']['type'] + r_offset = r['r_offset'] + text_addr + r_info_type = r['r_info_type'] + try: + # only for RELA sections + r_addend = r['r_addend'] + except KeyError: + r_addend = 0 + + # Default relocation type and name for logging + reloc_type = 'le32' + log_name = None + + if (env.arch.name == 'EM_386' and r_info_type in (R_386_PC32, R_386_PLT32) + or env.arch.name == 'EM_X86_64' and r_info_type in (R_X86_64_PC32, R_X86_64_PLT32) + or env.arch.name == 'EM_ARM' and r_info_type in (R_ARM_REL32, R_ARM_THM_CALL, R_ARM_THM_JUMP24) + or s_bind == 'STB_LOCAL' and env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_32 # not GOT + ): + # Standard relocation to fixed location within text/rodata + if hasattr(s, 'resolved'): + s = s.resolved + + sec = s.section + + if env.arch.separate_rodata and sec.name.startswith('.rodata'): + raise LinkError('fixed relocation to rodata with rodata referenced via GOT') + + if sec.name.startswith('.bss'): + raise LinkError('{}: fixed relocation to bss (bss variables can\'t be static)'.format(s.filename)) + + if sec.name.startswith('.external'): + raise LinkError('{}: fixed relocation to external symbol: {}'.format(s.filename, s.name)) + + addr = sec.addr + s['st_value'] + reloc = addr - r_offset + r_addend + + if r_info_type in (R_ARM_THM_CALL, R_ARM_THM_JUMP24): + # Both relocations have the same bit pattern to rewrite: + # R_ARM_THM_CALL: bl + # R_ARM_THM_JUMP24: b.w + reloc_type = 'thumb_b' + + elif (env.arch.name == 'EM_386' and r_info_type == R_386_GOTPC + or env.arch.name == 'EM_ARM' and r_info_type == R_ARM_BASE_PREL + ): + # Relocation to GOT address itself + assert s.name == '_GLOBAL_OFFSET_TABLE_' + addr = env.got_section.addr + reloc = addr - r_offset + r_addend + + elif (env.arch.name == 'EM_386' and r_info_type in (R_386_GOT32, R_386_GOT32X) + or env.arch.name == 'EM_ARM' and r_info_type == R_ARM_GOT_BREL + ): + # Relcation pointing to GOT + reloc = addr = env.got_entries[s.name].offset + + elif env.arch.name == 'EM_X86_64' and r_info_type == R_X86_64_REX_GOTPCRELX: + # Relcation pointing to GOT + got_entry = env.got_entries[s.name] + addr = env.got_section.addr + got_entry.offset + reloc = addr - r_offset + r_addend + + elif env.arch.name == 'EM_386' and r_info_type == R_386_GOTOFF: + # Relocation relative to GOT + addr = s.section.addr + s['st_value'] + reloc = addr - env.got_section.addr + r_addend + + elif env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_SLOT0_OP: + # Relocation pointing to GOT, xtensa specific + sec = s.section + if sec.name.startswith('.text'): + # it looks like R_XTENSA_SLOT0_OP into .text is already correctly relocated + return + assert sec.name.startswith('.literal'), sec.name + lit_idx = '{}+0x{:x}'.format(sec.filename, r_addend) + lit_ptr = env.xt_literals[lit_idx] + if isinstance(lit_ptr, str): + addr = env.got_section.addr + env.got_entries[lit_ptr].offset + log_name = 'GOT {}'.format(lit_ptr) + else: + addr = env.lit_section.addr + env.lit_entries[lit_ptr].offset + log_name = 'LIT' + reloc = addr - r_offset + reloc_type = 'xtensa_l32r' + + elif env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_DIFF32: + if s.section.name.startswith('.text'): + # it looks like R_XTENSA_DIFF32 into .text is already correctly relocated + return + assert 0 + + else: + # Unknown/unsupported relocation + assert 0, r_info_type + + # Write relocation + if reloc_type == 'le32': + existing, = struct.unpack_from('= 0x400000: # 2's complement + existing -= 0x800000 + new = existing + reloc + b_h = (b_h & 0xf800) | (new >> 12) & 0x7ff + b_l = (b_l & 0xf800) | (new >> 1) & 0x7ff + struct.pack_into('> 8 + l32r_imm16 = (l32r_imm16 + reloc >> 2) & 0xffff + l32r = l32r & 0xff | l32r_imm16 << 8 + pack_u24le(env.full_text, r_offset, l32r) + else: + assert 0, reloc_type + + # Log information about relocation + if log_name is None: + if s_type == 'STT_SECTION': + log_name = s.section.name + else: + log_name = s.name + log(LOG_LEVEL_3, ' {:08x} {} -> {:08x}'.format(r_offset, log_name, addr)) + +def do_relocation_data(env, text_addr, r): + s = r.sym + s_type = s.entry['st_info']['type'] + r_offset = r['r_offset'] + text_addr + r_info_type = r['r_info_type'] + try: + # only for RELA sections + r_addend = r['r_addend'] + except KeyError: + r_addend = 0 + + if (env.arch.name == 'EM_386' and r_info_type == R_386_32 + or env.arch.name == 'EM_X86_64' and r_info_type == R_X86_64_64 + or env.arch.name == 'EM_ARM' and r_info_type == R_ARM_ABS32 + or env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_32): + # Relocation in data.rel.ro to internal/external symbol + if env.arch.word_size == 4: + struct_type = ' {} {:08x}'.format(r_offset, log_name, addr)) + if env.arch.separate_rodata: + data = env.full_rodata + else: + data = env.full_text + existing, = struct.unpack_from(struct_type, data, r_offset) + if sec.name.startswith(('.text', '.rodata', '.data.rel.ro', '.bss')): + struct.pack_into(struct_type, data, r_offset, existing + addr) + kind = sec.name + elif sec.name == '.external.mp_fun_table': + assert addr == 0 + kind = s.mp_fun_table_offset + else: + assert 0, sec.name + if env.arch.separate_rodata: + base = '.rodata' + else: + base = '.text' + env.mpy_relocs.append((base, r_offset, kind)) + + else: + # Unknown/unsupported relocation + assert 0, r_info_type + +def load_object_file(env, felf): + with open(felf, 'rb') as f: + elf = elffile.ELFFile(f) + env.check_arch(elf['e_machine']) + + # Get symbol table + symtab = list(elf.get_section_by_name('.symtab').iter_symbols()) + + # Load needed sections from ELF file + sections_shndx = {} # maps elf shndx to Section object + for idx, s in enumerate(elf.iter_sections()): + if s.header.sh_type in ('SHT_PROGBITS', 'SHT_NOBITS'): + if s.data_size == 0: + # Ignore empty sections + pass + elif s.name.startswith(('.literal', '.text', '.rodata', '.data.rel.ro', '.bss')): + sec = Section.from_elfsec(s, felf) + sections_shndx[idx] = sec + if s.name.startswith('.literal'): + env.literal_sections.append(sec) + else: + env.sections.append(sec) + elif s.name.startswith('.data'): + raise LinkError('{}: {} non-empty'.format(felf, s.name)) + else: + # Ignore section + pass + elif s.header.sh_type in ('SHT_REL', 'SHT_RELA'): + shndx = s.header.sh_info + if shndx in sections_shndx: + sec = sections_shndx[shndx] + sec.reloc_name = s.name + sec.reloc = list(s.iter_relocations()) + for r in sec.reloc: + r.sym = symtab[r['r_info_sym']] + + # Link symbols to their sections, and update known and unresolved symbols + for sym in symtab: + sym.filename = felf + shndx = sym.entry['st_shndx'] + if shndx in sections_shndx: + # Symbol with associated section + sym.section = sections_shndx[shndx] + if sym['st_info']['bind'] == 'STB_GLOBAL': + # Defined global symbol + if sym.name in env.known_syms and not sym.name.startswith('__x86.get_pc_thunk.'): + raise LinkError('duplicate symbol: {}'.format(sym.name)) + env.known_syms[sym.name] = sym + elif sym.entry['st_shndx'] == 'SHN_UNDEF' and sym['st_info']['bind'] == 'STB_GLOBAL': + # Undefined global symbol, needs resolving + env.unresolved_syms.append(sym) + +def link_objects(env, native_qstr_vals_len, native_qstr_objs_len): + # Build GOT information + if env.arch.name == 'EM_XTENSA': + build_got_xtensa(env) + else: + build_got_generic(env) + + # Creat GOT section + got_size = len(env.got_entries) * env.arch.word_size + env.got_section = Section('GOT', bytearray(got_size), env.arch.word_size) + if env.arch.name == 'EM_XTENSA': + env.sections.insert(0, env.got_section) + else: + env.sections.append(env.got_section) + + # Create optional literal section + if env.arch.name == 'EM_XTENSA': + lit_size = len(env.lit_entries) * env.arch.word_size + env.lit_section = Section('LIT', bytearray(lit_size), env.arch.word_size) + env.sections.insert(1, env.lit_section) + + # Create section to contain mp_native_qstr_val_table + env.qstr_val_section = Section('.text.QSTR_VAL', bytearray(native_qstr_vals_len * env.arch.qstr_entry_size), env.arch.qstr_entry_size) + env.sections.append(env.qstr_val_section) + + # Create section to contain mp_native_qstr_obj_table + env.qstr_obj_section = Section('.text.QSTR_OBJ', bytearray(native_qstr_objs_len * env.arch.word_size), env.arch.word_size) + env.sections.append(env.qstr_obj_section) + + # Resolve unknown symbols + mp_fun_table_sec = Section('.external.mp_fun_table', b'', 0) + fun_table = {key: 67 + idx + for idx, key in enumerate([ + 'mp_type_type', + 'mp_type_str', + 'mp_type_list', + 'mp_type_dict', + 'mp_type_fun_builtin_0', + 'mp_type_fun_builtin_1', + 'mp_type_fun_builtin_2', + 'mp_type_fun_builtin_3', + 'mp_type_fun_builtin_var', + 'mp_stream_read_obj', + 'mp_stream_readinto_obj', + 'mp_stream_unbuffered_readline_obj', + 'mp_stream_write_obj', + ]) + } + for sym in env.unresolved_syms: + assert sym['st_value'] == 0 + if sym.name == '_GLOBAL_OFFSET_TABLE_': + pass + elif sym.name == 'mp_fun_table': + sym.section = Section('.external', b'', 0) + elif sym.name == 'mp_native_qstr_val_table': + sym.section = env.qstr_val_section + elif sym.name == 'mp_native_qstr_obj_table': + sym.section = env.qstr_obj_section + elif sym.name in env.known_syms: + sym.resolved = env.known_syms[sym.name] + else: + if sym.name in fun_table: + sym.section = mp_fun_table_sec + sym.mp_fun_table_offset = fun_table[sym.name] + else: + raise LinkError('{}: undefined symbol: {}'.format(sym.filename, sym.name)) + + # Align sections, assign their addresses, and create full_text + env.full_text = bytearray(env.arch.asm_jump(8)) # dummy, to be filled in later + env.full_rodata = bytearray(0) + env.full_bss = bytearray(0) + for sec in env.sections: + if env.arch.separate_rodata and sec.name.startswith(('.rodata', '.data.rel.ro')): + data = env.full_rodata + elif sec.name.startswith('.bss'): + data = env.full_bss + else: + data = env.full_text + sec.addr = align_to(len(data), sec.alignment) + data.extend(b'\x00' * (sec.addr - len(data))) + data.extend(sec.data) + + env.print_sections() + + populate_got(env) + if env.arch.name == 'EM_XTENSA': + populate_lit(env) + + # Fill in relocations + for sec in env.sections: + if not sec.reloc: + continue + log(LOG_LEVEL_3, '{}: {} relocations via {}:'.format(sec.filename, sec.name, sec.reloc_name)) + for r in sec.reloc: + if sec.name.startswith(('.text', '.rodata')): + do_relocation_text(env, sec.addr, r) + elif sec.name.startswith('.data.rel.ro'): + do_relocation_data(env, sec.addr, r) + else: + assert 0, sec.name + +################################################################################ +# .mpy output + +class MPYOutput: + def open(self, fname): + self.f = open(fname, 'wb') + self.prev_base = -1 + self.prev_offset = -1 + + def close(self): + self.f.close() + + def write_bytes(self, buf): + self.f.write(buf) + + def write_uint(self, val): + b = bytearray() + b.insert(0, val & 0x7f) + val >>= 7 + while val: + b.insert(0, 0x80 | (val & 0x7f)) + val >>= 7 + self.write_bytes(b) + + def write_qstr(self, s): + if s in qstrutil.static_qstr_list: + self.write_bytes(bytes([0, qstrutil.static_qstr_list.index(s) + 1])) + else: + s = bytes(s, 'ascii') + self.write_uint(len(s) << 1) + self.write_bytes(s) + + def write_reloc(self, base, offset, dest, n): + need_offset = not (base == self.prev_base and offset == self.prev_offset + 1) + self.prev_offset = offset + n - 1 + if dest <= 2: + dest = (dest << 1) | (n > 1) + else: + assert 6 <= dest <= 127 + assert n == 1 + dest = dest << 1 | need_offset + assert 0 <= dest <= 0xfe, dest + self.write_bytes(bytes([dest])) + if need_offset: + if base == '.text': + base = 0 + elif base == '.rodata': + base = 1 + self.write_uint(offset << 1 | base) + if n > 1: + self.write_uint(n) + +def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs): + # Write jump instruction to start of text + jump = env.arch.asm_jump(entry_offset) + env.full_text[:len(jump)] = jump + + log(LOG_LEVEL_1, 'arch: {}'.format(env.arch.name)) + log(LOG_LEVEL_1, 'text size: {}'.format(len(env.full_text))) + if len(env.full_rodata): + log(LOG_LEVEL_1, 'rodata size: {}'.format(len(env.full_rodata))) + log(LOG_LEVEL_1, 'bss size: {}'.format(len(env.full_bss))) + log(LOG_LEVEL_1, 'GOT entries: {}'.format(len(env.got_entries))) + + #xxd(env.full_text) + + out = MPYOutput() + out.open(fmpy) + + # MPY: header + out.write_bytes(bytearray([ + ord('M'), + MPY_VERSION, + env.arch.mpy_feature, + MP_SMALL_INT_BITS, + QSTR_WINDOW_SIZE, + ])) + + # MPY: kind/len + out.write_uint(len(env.full_text) << 2 | (MP_CODE_NATIVE_VIPER - MP_CODE_BYTECODE)) + + # MPY: machine code + out.write_bytes(env.full_text) + + # MPY: n_qstr_link (assumes little endian) + out.write_uint(len(native_qstr_vals) + len(native_qstr_objs)) + for q in range(len(native_qstr_vals)): + off = env.qstr_val_section.addr + q * env.arch.qstr_entry_size + out.write_uint(off << 2) + out.write_qstr(native_qstr_vals[q]) + for q in range(len(native_qstr_objs)): + off = env.qstr_obj_section.addr + q * env.arch.word_size + out.write_uint(off << 2 | 3) + out.write_qstr(native_qstr_objs[q]) + + # MPY: scope_flags + scope_flags = MP_SCOPE_FLAG_VIPERRELOC + if len(env.full_rodata): + scope_flags |= MP_SCOPE_FLAG_VIPERRODATA + if len(env.full_bss): + scope_flags |= MP_SCOPE_FLAG_VIPERBSS + out.write_uint(scope_flags) + + # MPY: n_obj + out.write_uint(0) + + # MPY: n_raw_code + out.write_uint(0) + + # MPY: rodata and/or bss + if len(env.full_rodata): + rodata_const_table_idx = 1 + out.write_uint(len(env.full_rodata)) + out.write_bytes(env.full_rodata) + if len(env.full_bss): + bss_const_table_idx = bool(env.full_rodata) + 1 + out.write_uint(len(env.full_bss)) + + # MPY: relocation information + prev_kind = None + for base, addr, kind in env.mpy_relocs: + if isinstance(kind, str) and kind.startswith('.text'): + kind = 0 + elif kind in ('.rodata', '.data.rel.ro'): + if env.arch.separate_rodata: + kind = rodata_const_table_idx + else: + kind = 0 + elif isinstance(kind, str) and kind.startswith('.bss'): + kind = bss_const_table_idx + elif kind == 'mp_fun_table': + kind = 6 + else: + kind = 7 + kind + assert addr % env.arch.word_size == 0, addr + offset = addr // env.arch.word_size + if kind == prev_kind and base == prev_base and offset == prev_offset + 1: + prev_n += 1 + prev_offset += 1 + else: + if prev_kind is not None: + out.write_reloc(prev_base, prev_offset - prev_n + 1, prev_kind, prev_n) + prev_kind = kind + prev_base = base + prev_offset = offset + prev_n = 1 + if prev_kind is not None: + out.write_reloc(prev_base, prev_offset - prev_n + 1, prev_kind, prev_n) + + # MPY: sentinel for end of relocations + out.write_bytes(b'\xff') + + out.close() + +################################################################################ +# main + +def do_preprocess(args): + if args.output is None: + assert args.files[0].endswith('.c') + args.output = args.files[0][:-1] + 'config.h' + static_qstrs, qstr_vals, qstr_objs = extract_qstrs(args.files) + with open(args.output, 'w') as f: + print('#include \n' + 'typedef uintptr_t mp_uint_t;\n' + 'typedef intptr_t mp_int_t;\n' + 'typedef uintptr_t mp_off_t;', file=f) + for i, q in enumerate(static_qstrs): + print('#define %s (%u)' % (q, i + 1), file=f) + for i, q in enumerate(sorted(qstr_vals)): + print('#define %s (mp_native_qstr_val_table[%d])' % (q, i), file=f) + for i, q in enumerate(sorted(qstr_objs)): + print('#define MP_OBJ_NEW_QSTR_%s ((mp_obj_t)mp_native_qstr_obj_table[%d])' % (q, i), file=f) + if args.arch == 'xtensawin': + qstr_type = 'uint32_t' # esp32 can only read 32-bit values from IRAM + else: + qstr_type = 'uint16_t' + print('extern const {} mp_native_qstr_val_table[];'.format(qstr_type), file=f) + print('extern const mp_uint_t mp_native_qstr_obj_table[];', file=f) + +def do_link(args): + if args.output is None: + assert args.files[0].endswith('.o') + args.output = args.files[0][:-1] + 'mpy' + native_qstr_vals = [] + native_qstr_objs = [] + if args.qstrs is not None: + with open(args.qstrs) as f: + for l in f: + m = re.match(r'#define MP_QSTR_([A-Za-z0-9_]*) \(mp_native_', l) + if m: + native_qstr_vals.append(m.group(1)) + else: + m = re.match(r'#define MP_OBJ_NEW_QSTR_MP_QSTR_([A-Za-z0-9_]*)', l) + if m: + native_qstr_objs.append(m.group(1)) + log(LOG_LEVEL_2, 'qstr vals: ' + ', '.join(native_qstr_vals)) + log(LOG_LEVEL_2, 'qstr objs: ' + ', '.join(native_qstr_objs)) + env = LinkEnv(args.arch) + try: + for file in args.files: + load_object_file(env, file) + link_objects(env, len(native_qstr_vals), len(native_qstr_objs)) + build_mpy(env, env.find_addr('mpy_init'), args.output, native_qstr_vals, native_qstr_objs) + except LinkError as er: + print('LinkError:', er.args[0]) + sys.exit(1) + +def main(): + import argparse + cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.') + cmd_parser.add_argument('--verbose', '-v', action='count', default=1, help='increase verbosity') + cmd_parser.add_argument('--arch', default='x64', help='architecture') + cmd_parser.add_argument('--preprocess', action='store_true', help='preprocess source files') + cmd_parser.add_argument('--qstrs', default=None, help='file defining additional qstrs') + cmd_parser.add_argument('--output', '-o', default=None, help='output .mpy file (default to input with .o->.mpy)') + cmd_parser.add_argument('files', nargs='+', help='input files') + args = cmd_parser.parse_args() + + global log_level + log_level = args.verbose + + if args.preprocess: + do_preprocess(args) + else: + do_link(args) + +if __name__ == '__main__': + main() diff --git a/micropython/tools/pyboard.py b/micropython/tools/pyboard.py index d906235..2a255e9 100755 --- a/micropython/tools/pyboard.py +++ b/micropython/tools/pyboard.py @@ -4,7 +4,7 @@ # # The MIT License (MIT) # -# Copyright (c) 2014-2016 Damien P. George +# Copyright (c) 2014-2019 Damien P. George # Copyright (c) 2017 Paul Sokolovsky # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -363,8 +363,8 @@ def eval(self, expression): ret = ret.strip() return ret - def exec_(self, command): - ret, ret_err = self.exec_raw(command) + def exec_(self, command, data_consumer=None): + ret, ret_err = self.exec_raw(command, data_consumer=data_consumer) if ret_err: raise PyboardError('exception', ret, ret_err) return ret @@ -378,6 +378,52 @@ def get_time(self): t = str(self.eval('pyb.RTC().datetime()'), encoding='utf8')[1:-1].split(', ') return int(t[4]) * 3600 + int(t[5]) * 60 + int(t[6]) + def fs_ls(self, src): + cmd = "import uos\nfor f in uos.ilistdir(%s):\n" \ + " print('{:12} {}{}'.format(f[3]if len(f)>3 else 0,f[0],'/'if f[1]&0x4000 else ''))" % \ + (("'%s'" % src) if src else '') + self.exec_(cmd, data_consumer=stdout_write_bytes) + + def fs_cat(self, src, chunk_size=256): + cmd = "with open('%s') as f:\n while 1:\n" \ + " b=f.read(%u)\n if not b:break\n print(b,end='')" % (src, chunk_size) + self.exec_(cmd, data_consumer=stdout_write_bytes) + + def fs_get(self, src, dest, chunk_size=256): + self.exec_("f=open('%s','rb')\nr=f.read" % src) + with open(dest, 'wb') as f: + while True: + data = bytearray() + self.exec_("print(r(%u))" % chunk_size, data_consumer=lambda d:data.extend(d)) + assert data.endswith(b'\r\n\x04') + data = eval(str(data[:-3], 'ascii')) + if not data: + break + f.write(data) + self.exec_("f.close()") + + def fs_put(self, src, dest, chunk_size=256): + self.exec_("f=open('%s','wb')\nw=f.write" % dest) + with open(src, 'rb') as f: + while True: + data = f.read(chunk_size) + if not data: + break + if sys.version_info < (3,): + self.exec_('w(b' + repr(data) + ')') + else: + self.exec_('w(' + repr(data) + ')') + self.exec_("f.close()") + + def fs_mkdir(self, dir): + self.exec_("import uos\nuos.mkdir('%s')" % dir) + + def fs_rmdir(self, dir): + self.exec_("import uos\nuos.rmdir('%s')" % dir) + + def fs_rm(self, src): + self.exec_("import uos\nuos.remove('%s')" % src) + # in Python2 exec is a keyword so one must use "exec_" # but for Python3 we want to provide the nicer version "exec" setattr(Pyboard, "exec", Pyboard.exec_) @@ -390,6 +436,81 @@ def execfile(filename, device='/dev/ttyACM0', baudrate=115200, user='micro', pas pyb.exit_raw_repl() pyb.close() +def filesystem_command(pyb, args): + def fname_remote(src): + if src.startswith(':'): + src = src[1:] + return src + def fname_cp_dest(src, dest): + src = src.rsplit('/', 1)[-1] + if dest is None or dest == '': + dest = src + elif dest == '.': + dest = './' + src + elif dest.endswith('/'): + dest += src + return dest + + cmd = args[0] + args = args[1:] + try: + if cmd == 'cp': + srcs = args[:-1] + dest = args[-1] + if srcs[0].startswith('./') or dest.startswith(':'): + op = pyb.fs_put + fmt = 'cp %s :%s' + dest = fname_remote(dest) + else: + op = pyb.fs_get + fmt = 'cp :%s %s' + for src in srcs: + src = fname_remote(src) + dest2 = fname_cp_dest(src, dest) + print(fmt % (src, dest2)) + op(src, dest2) + else: + op = {'ls': pyb.fs_ls, 'cat': pyb.fs_cat, 'mkdir': pyb.fs_mkdir, + 'rmdir': pyb.fs_rmdir, 'rm': pyb.fs_rm}[cmd] + if cmd == 'ls' and not args: + args = [''] + for src in args: + src = fname_remote(src) + print('%s :%s' % (cmd, src)) + op(src) + except PyboardError as er: + print(str(er.args[2], 'ascii')) + pyb.exit_raw_repl() + pyb.close() + sys.exit(1) + +_injected_import_hook_code = """\ +import uos, uio +class _FS: + class File(uio.IOBase): + def __init__(self): + self.off = 0 + def ioctl(self, request, arg): + return 0 + def readinto(self, buf): + buf[:] = memoryview(_injected_buf)[self.off:self.off + len(buf)] + self.off += len(buf) + return len(buf) + mount = umount = chdir = lambda *args: None + def stat(self, path): + if path == '_injected.mpy': + return tuple(0 for _ in range(10)) + else: + raise OSError(-2) # ENOENT + def open(self, path, mode): + return self.File() +uos.mount(_FS(), '/_') +uos.chdir('/_') +from _injected import * +uos.umount('/_') +del _injected_buf, _FS +""" + def main(): import argparse cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.') @@ -400,6 +521,7 @@ def main(): cmd_parser.add_argument('-c', '--command', help='program passed in as string') cmd_parser.add_argument('-w', '--wait', default=0, type=int, help='seconds to wait for USB connected board to become available') cmd_parser.add_argument('--follow', action='store_true', help='follow the output after running the scripts [default if no scripts given]') + cmd_parser.add_argument('-f', '--filesystem', action='store_true', help='perform a filesystem action') cmd_parser.add_argument('files', nargs='*', help='input files') args = cmd_parser.parse_args() @@ -411,7 +533,7 @@ def main(): sys.exit(1) # run any command or file(s) - if args.command is not None or len(args.files): + if args.command is not None or args.filesystem or len(args.files): # we must enter raw-REPL mode to execute commands # this will do a soft-reset of the board try: @@ -436,6 +558,11 @@ def execbuffer(buf): stdout_write_bytes(ret_err) sys.exit(1) + # do filesystem commands, if given + if args.filesystem: + filesystem_command(pyb, args.files) + args.files.clear() + # run the command, if given if args.command is not None: execbuffer(args.command.encode('utf-8')) @@ -444,13 +571,16 @@ def execbuffer(buf): for filename in args.files: with open(filename, 'rb') as f: pyfile = f.read() + if filename.endswith('.mpy') and pyfile[0] == ord('M'): + pyb.exec_('_injected_buf=' + repr(pyfile)) + pyfile = _injected_import_hook_code execbuffer(pyfile) # exiting raw-REPL just drops to friendly-REPL mode pyb.exit_raw_repl() # if asked explicitly, or no files given, then follow the output - if args.follow or (args.command is None and len(args.files) == 0): + if args.follow or (args.command is None and not args.filesystem and len(args.files) == 0): try: ret, ret_err = pyb.follow(timeout=None, data_consumer=stdout_write_bytes) except PyboardError as er: diff --git a/micropython/tools/tinytest-codegen.py b/micropython/tools/tinytest-codegen.py index ad3b3bb..424f70a 100755 --- a/micropython/tools/tinytest-codegen.py +++ b/micropython/tools/tinytest-codegen.py @@ -33,8 +33,10 @@ def script_to_map(test_file): "void {name}(void* data) {{\n" " static const char pystr[] = {script};\n" " static const char exp[] = {output};\n" + ' printf("\\n");\n' " upytest_set_expected_output(exp, sizeof(exp) - 1);\n" " upytest_execute_test(pystr);\n" + ' printf("result: ");\n' "}}" ) @@ -54,7 +56,7 @@ def script_to_map(test_file): ## XXX: may be we could have `--without ` argument... # currently these tests are selected because they pass on qemu-arm -test_dirs = ('basics', 'micropython', 'float', 'extmod', 'inlineasm') # 'import', 'io', 'misc') +test_dirs = ('basics', 'micropython', 'misc', 'extmod', 'float', 'inlineasm', 'qemu-arm',) # 'import', 'io',) exclude_tests = ( # pattern matching in .exp 'basics/bytes_compare3.py', @@ -81,6 +83,12 @@ def script_to_map(test_file): 'micropython/heapalloc_traceback.py', # pattern matching in .exp 'micropython/meminfo.py', + # needs sys stdfiles + 'misc/print_exception.py', + # settrace .exp files are too large + 'misc/sys_settrace_loop.py', + 'misc/sys_settrace_generator.py', + 'misc/sys_settrace_features.py', ) output = [] diff --git a/micropython/tools/uf2conv.py b/micropython/tools/uf2conv.py new file mode 100755 index 0000000..2f2812a --- /dev/null +++ b/micropython/tools/uf2conv.py @@ -0,0 +1,319 @@ +#!/usr/bin/env python3 + +# Microsoft UF2 +# +# The MIT License (MIT) +# +# Copyright (c) Microsoft Corporation +# +# All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import sys +import struct +import subprocess +import re +import os +import os.path +import argparse + + +UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" +UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected +UF2_MAGIC_END = 0x0AB16F30 # Ditto + +families = { + 'SAMD21': 0x68ed2b88, + 'SAMD51': 0x55114460, + 'NRF52': 0x1b57745f, + 'STM32F1': 0x5ee21072, + 'STM32F4': 0x57755a57, + 'ATMEGA32': 0x16573617, +} + +INFO_FILE = "/INFO_UF2.TXT" + +appstartaddr = 0x2000 +familyid = 0x0 + + +def is_uf2(buf): + w = struct.unpack(" 476: + assert False, "Invalid UF2 data size at " + ptr + newaddr = hd[3] + if curraddr == None: + appstartaddr = newaddr + curraddr = newaddr + padding = newaddr - curraddr + if padding < 0: + assert False, "Block out of order at " + ptr + if padding > 10*1024*1024: + assert False, "More than 10M of padding needed at " + ptr + if padding % 4 != 0: + assert False, "Non-word padding size at " + ptr + while padding > 0: + padding -= 4 + outp += b"\x00\x00\x00\x00" + outp += block[32 : 32 + datalen] + curraddr = newaddr + datalen + return outp + +def convert_to_carray(file_content): + outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {" + for i in range(len(file_content)): + if i % 16 == 0: + outp += "\n" + outp += "0x%02x, " % ord(file_content[i]) + outp += "\n};\n" + return outp + +def convert_to_uf2(file_content): + global familyid + datapadding = b"" + while len(datapadding) < 512 - 256 - 32 - 4: + datapadding += b"\x00\x00\x00\x00" + numblocks = (len(file_content) + 255) // 256 + outp = b"" + for blockno in range(numblocks): + ptr = 256 * blockno + chunk = file_content[ptr:ptr + 256] + flags = 0x0 + if familyid: + flags |= 0x2000 + hd = struct.pack(b"= 3 and words[1] == "2" and words[2] == "FAT": + drives.append(words[0]) + else: + rootpath = "/media" + if sys.platform == "darwin": + rootpath = "/Volumes" + elif sys.platform == "linux": + tmp = rootpath + "/" + os.environ["USER"] + if os.path.isdir(tmp): + rootpath = tmp + for d in os.listdir(rootpath): + drives.append(os.path.join(rootpath, d)) + + + def has_info(d): + try: + return os.path.isfile(d + INFO_FILE) + except: + return False + + return list(filter(has_info, drives)) + + +def board_id(path): + with open(path + INFO_FILE, mode='r') as file: + file_content = file.read() + return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) + + +def list_drives(): + for d in get_drives(): + print(d, board_id(d)) + + +def write_file(name, buf): + with open(name, "wb") as f: + f.write(buf) + print("Wrote %d bytes to %s." % (len(buf), name)) + + +def main(): + global appstartaddr, familyid + def error(msg): + print(msg) + sys.exit(1) + parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') + parser.add_argument('input', metavar='INPUT', type=str, nargs='?', + help='input file (HEX, BIN or UF2)') + parser.add_argument('-b' , '--base', dest='base', type=str, + default="0x2000", + help='set base address of application for BIN format (default: 0x2000)') + parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str, + help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') + parser.add_argument('-d' , '--device', dest="device_path", + help='select a device path to flash') + parser.add_argument('-l' , '--list', action='store_true', + help='list connected devices') + parser.add_argument('-c' , '--convert', action='store_true', + help='do not flash, just convert') + parser.add_argument('-f' , '--family', dest='family', type=str, + default="0x0", + help='specify familyID - number or name (default: 0x0)') + parser.add_argument('-C' , '--carray', action='store_true', + help='convert binary file to a C array, not UF2') + args = parser.parse_args() + appstartaddr = int(args.base, 0) + + if args.family.upper() in families: + familyid = families[args.family.upper()] + else: + try: + familyid = int(args.family, 0) + except ValueError: + error("Family ID needs to be a number or one of: " + ", ".join(families.keys())) + + if args.list: + list_drives() + else: + if not args.input: + error("Need input file") + with open(args.input, mode='rb') as f: + inpbuf = f.read() + from_uf2 = is_uf2(inpbuf) + ext = "uf2" + if from_uf2: + outbuf = convert_from_uf2(inpbuf) + ext = "bin" + elif is_hex(inpbuf): + outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8")) + elif args.carray: + outbuf = convert_to_carray(inpbuf) + ext = "h" + else: + outbuf = convert_to_uf2(inpbuf) + print("Converting to %s, output size: %d, start address: 0x%x" % + (ext, len(outbuf), appstartaddr)) + if args.convert: + drives = [] + if args.output == None: + args.output = "flash." + ext + else: + drives = get_drives() + + if args.output: + write_file(args.output, outbuf) + else: + if len(drives) == 0: + error("No drive to deploy.") + for d in drives: + print("Flashing %s (%s)" % (d, board_id(d))) + write_file(d + "/NEW.UF2", outbuf) + + +if __name__ == "__main__": + main() diff --git a/mklittlefs/mklfs.c b/mklittlefs/mklfs.c index 3982b62..fc5bc69 100644 --- a/mklittlefs/mklfs.c +++ b/mklittlefs/mklfs.c @@ -308,7 +308,7 @@ int save_image(void) for (size=LITTLEFS_IMAGE_SIZE-1; size>0; size--) { if (lfs_image[size] != 0xFF) break; } - int img_size = ((size / 4096) * 4096) + 4096; + int img_size = ((size / 65536) * 65536) + 65536; printf("Image size: %d (%d)\r\n", size, img_size); printf("Saving image to '%s'\r\n", image_name); @@ -356,6 +356,12 @@ int lfs_img_mount(void) } printf(" Image file formated.\r\n"); + err = lfs_unmount(&lfs); + if (err) { + printf("Error unmounting image (%d)\r\n", err); + return err; + } + err = lfs_mount(&lfs, &config); if (err) { printf("Error mounting image (%d)\r\n", err);