├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── common ├── CMakeLists.txt ├── start.S ├── syscalls.c └── vectors.S ├── examples ├── blink │ ├── CMakeLists.txt │ ├── README.md │ ├── blink.c │ └── gdbinit └── hello_world │ ├── CMakeLists.txt │ ├── README.md │ ├── gdbinit │ └── hello_world.c ├── hal ├── CMakeLists.txt ├── README.md └── sdkconfig.h.in ├── img ├── esp32c3-directboot.svg └── esp32h2-directboot.svg ├── ld ├── esp32c3 │ ├── common.ld │ ├── memory.ld │ └── romfuncs.ld └── esp32h2 │ ├── common.ld │ ├── memory.ld │ └── romfuncs.ld ├── toolchain-rv32.cmake └── utils.cmake /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: 'build' 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-22.04 12 | strategy: 13 | matrix: 14 | target: [esp32c3, esp32h2] 15 | example: ["blink", "hello_world"] 16 | include: 17 | - target: esp32c3 18 | example: "blink" 19 | expected_size: 7436 20 | - target: esp32c3 21 | example: "hello_world" 22 | expected_size: 10216 23 | - target: esp32h2 24 | example: "blink" 25 | expected_size: 4561 26 | - target: esp32h2 27 | example: "hello_world" 28 | expected_size: 8484 29 | steps: 30 | - uses: actions/checkout@v2 31 | - name: Build ${{ matrix.example }} for ${{ matrix.target }} 32 | shell: bash 33 | run: | 34 | export TOOLCHAIN_VERSION="12.2.0-3" 35 | export TOOLCHAIN_DIR="xpack-riscv-none-elf-gcc-${TOOLCHAIN_VERSION}" 36 | export TOOLCHAIN_ARCHIVE="${TOOLCHAIN_DIR}-linux-x64.tar.gz" 37 | export TOOLCHAIN_URL="https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v${TOOLCHAIN_VERSION}/${TOOLCHAIN_ARCHIVE}" 38 | wget --no-verbose ${TOOLCHAIN_URL} 39 | tar xf ${TOOLCHAIN_ARCHIVE} 40 | export PATH=$PWD/${TOOLCHAIN_DIR}/bin:$PATH 41 | cd examples/${{ matrix.example }} 42 | mkdir -p build 43 | cmake -S . -B build -D target=${{ matrix.target }} 44 | cmake --build build 45 | bin_size=$(stat --format="%s" build/${{ matrix.example }}.bin) 46 | expected_size=${{ matrix.expected_size }} 47 | size_tolerance=500 48 | echo "Binary size for ${{ matrix.example }} example: ${bin_size}, expected: ${expected_size}" 49 | test ${bin_size} -gt $(($expected_size - $size_tolerance)) || (echo "binary seems too small"; exit 1) 50 | test ${bin_size} -lt $(($expected_size + $size_tolerance)) || (echo "binary seems too large"; exit 1) 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Direct Boot example 2 | 3 | Supported chips: ESP32-C3, ESP32-H2 4 | 5 | This is an example of "direct boot" feature. 6 | It allows an application to be executed directly from flash, without using the 2nd stage bootloader. 7 | 8 | ## Background 9 | 10 | ESP8266 and ESP32 series of chips share the common [binary image format](https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/firmware-image-format.html). This format describes how the binary image stored in flash should be loaded into IRAM/DRAM by the ROM bootloader. In typical applications, the ROM bootloader doesn't load the application binary directly. Instead, it loads the 2nd stage bootloader into RAM. The 2nd stage bootloader then loads the application: sections which should reside in RAM are copied from flash into RAM, and cache MMU is configured to map the remaining sections, which are accessed from flash. 11 | 12 | Compared to other microcontrollers, where the program in flash is executed directly without the need for additional stages of bootloaders, this arrangement does add complexity. However, it should be noted that in most production applications the 2nd stage bootloader is required to support firmware update, rollback, and security features. Because of this, the 2nd stage bootloader is used in ESP-IDF, despite the extra complexity. 13 | 14 | ## Direct boot feature 15 | 16 | Chips, supported in this example (for example, ESP32-C3, starting from silicon revision 3) allow an application stored in flash to be executed directly, without being copied into RAM. This makes it possible to link an application with a relatively simple linker script, and produce the binary using `objcopy` command, then flash the resulting binary to the target chip. 17 | 18 | Direct boot feature is activated under the following conditions: 19 | * Secure boot is disabled. 20 | * Direct boot feature is not disabled via `EFUSE_DIS_LEGACY_SPI_BOOT` eFuse bit. 21 | * The ROM bootloader doesn't detect a valid binary image [in the usual format](https://github.com/espressif/esptool/wiki/Firmware-Image-Format) 22 | * The first 8 bytes in flash are `1d 04 db ae 1d 04 db ae` — that is a "magic number" 0xaedb041d repeated twice. 23 | 24 | In this case, the ROM bootloader sets up Flash MMU to map all amount of Flash then jumps to address `Flash address + 8`, i.e. to the instruction at offset 8 in flash, immediately after the magic numbers. 25 | 26 | For example, the ROM bootloader of ESP32-C3 sets up Flash MMU to map 4 MB of Flash to addresses 0x42000000 (for code execution) and 0x3C000000 (for read-only data access). 27 | 28 | The application entry function needs to: 29 | 1. set up global pointer register 30 | 2. set up stack pointer register 31 | 3. zero-initialize the .bss section 32 | 4. initialize the .data section, copying it from ROM 33 | 5. write the vector table address to the MTVEC register (optional) 34 | 6. call C library initialization (optional) 35 | 7. call the `main` function 36 | 37 | The `_start` function provided by newlib C library performs all these steps, except for the .data section initialization. 38 | 39 | ## When to use direct boot? 40 | 41 | Direct boot feature is provided primarily to simplify the initial porting process of new languages, frameworks, and execution environments. 42 | 43 | Use it if all of the below are true: 44 | 45 | * ESP-IDF environment can't be used. 46 | * The code doesn't fit into RAM, therefore execution from flash is required. 47 | * Dependency on the ESP-specific binary image format or the ESP-IDF 2nd stage bootloader is undesirable. 48 | 49 | This feature can also be useful in an educational context to "hide" the added complexity of chip Flash MMU and cache configuration. 50 | 51 | ## Alternatives to direct boot 52 | 53 | If the entire application code is small enough to fit into RAM, then the direct boot feature is not required. Instead, the ELF file can be loaded into the chip using one of the following methods: 54 | 55 | * With GDB `load` command, over JTAG. 56 | * With `esptool.py load_ram` command, over UART. 57 | * By converting the ELF file to binary using `esptool.py elf2image` and then writing the binary into flash. 58 | 59 | ## Example overview 60 | 61 | This example contains the following parts: 62 | 63 | * [common/](common/) directory with the application entrypoint, placeholder for the vector table, and a simple implementation of `_write` syscall. 64 | * [examples/blink/](examples/blink/) directory with an example project which blinks an LED. 65 | * [examples/hello_world/](examples/hello_world/) directory with the minimal example project which prints "Hello, world!" to the UART. 66 | * [img/](img/) directory with *.svg format diagrams which illustrate the run-time memory layout and binary image layout when direct boot is used. 67 | * [ld/](ld/) directory with the linker scripts. 68 | 69 | 70 | ## Prerequisites 71 | 72 | ### Cross-compiler 73 | 74 | Download and install `riscv-none-elf-gcc` toolchain, for example from the [xPack project](https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases). 75 | 76 | This example has been built and tested with toolchain release `12.2.0-3`. 77 | 78 | Make sure the toolchain is added to your `PATH`. 79 | 80 | A different RISC-V toolchain can also be used, in this case you need to adjust [toolchain-rv32.cmake](toolchain-rv32.cmake). 81 | 82 | ### Build tools 83 | 84 | This example uses CMake. Make sure that CMake and your build system of choice (e.g., Ninja or GNU Make) are also added to your `PATH`. 85 | 86 | ### esptool.py 87 | 88 | To flash binaries into the chip, [esptool.py](https://github.com/espressif/esptool) is used. 89 | 90 | If you have Python and pip installed, you can install esptool using: 91 | ```bash 92 | pip install --user esptool 93 | ``` 94 | 95 | Windows users may alternatively download a pre-built executable from the [releases](https://github.com/espressif/esptool/releases) page. These executables don't require Python to be installed. 96 | 97 | ## Building and running the examples 98 | 99 | See README.md files in example directories for instructions: 100 | * [blink](examples/blink/README.md) 101 | * [hello_world](examples/hello_world/README.md) 102 | 103 | ## Debugging using JTAG and GDB 104 | 105 | To debug the examples using JTAG and GDB, follow these steps: 106 | 107 | 1. Install OpenOCD from https://github.com/espressif/openocd-esp32/releases. (At the time of writing, the upstream version of OpenOCD includes Espressif Xtensa-based chips, but not RISC-V ones, yet.) 108 | 2. Add openocd to `PATH` 109 | 3. Build one of the examples (for instance, `blink`), then launch GDB like this: 110 | ``` 111 | riscv-none-elf-gdb -x gdbinit build/blink 112 | ``` 113 | This will use the provided gdbinit file to: 114 | - Launch OpenOCD in pipe mode. Adjust the `gdbinit` file if you need to change OpenOCD launch configuration or select another target chip. You can also launch OpenOCD manually, in that case use `target extended-remote :3333` in `gdbinit`. 115 | - Flash the program over JTAG 116 | - Reset the target 117 | - Set a temporary breakpoint at `main` 118 | - Run until the breakpoint 119 | 4. Now you can use GDB commands to step through the code as usual. 120 | 121 | ## Memory layout 122 | 123 | ### ESP32-C3 124 | 125 | The sections shown in blue on the left are parts of the flash image. 126 | 127 | ![img/esp32c3-directboot.svg](img/esp32c3-directboot.svg) 128 | 129 | ROM bootloader maps the 0 – 4 MB region of flash to the CPU address space twice: to the "DROM" region using the data cache, and to the "IROM" region using the instruction cache. 130 | 131 | As it is obvious from the diagram, some parts of this mapping are unnecessary. These parts are shown in gray on the right. For example, `.text` section gets mapped not only to the IROM, but also to DROM, even though code execution only happens through IROM. 132 | 133 | Such uniform mapping was chosen simply because it is universal, and can be set up by the ROM code without any prior knowledge about the application being loaded. This mapping isn't in any way a limitation of ESP32-C3 cache hardware; for example, ESP-IDF 2nd stage bootloader maps only those regions which are necessary in the given part of the address space. 134 | 135 | The run-time memory layout and flash binary image layout shown above are achieved in the linker script ([ld/esp32c3/common.ld](ld/esp32c3/common.ld)) by specifying the LMAs (load addresses). LMAs start at 0, and match the addresses in flash. VMAs for IROM (`entry` and `.text`) and DROM (`.rodata`) sections are set in such a way that LMA == VMA - BASE, where *BASE* is the starting address of IROM or DROM. Non-cached `.data` section is then added at the next available LMA. 136 | 137 | ### ESP32-H2 138 | 139 | ![img/esp32h2-directboot.svg](img/esp32h2-directboot.svg) 140 | 141 | ROM bootloader maps the 0 – 4 MB region of flash to the CPU address space using the cache and the Flash MMU. 142 | 143 | The memory layout can be found in liker script ([ld/esp32h2/memory.ld](ld/esp32h2/memory.ld)). 144 | 145 | The run-time memory layout and flash binary image layout shown above are achieved in the linker script ([ld/esp32h2/common.ld](ld/esp32h2/common.ld)) by specifying the LMAs (load addresses). LMAs start at 0, and match the addresses in flash. VMAs for ROM (`entry`, `.text` and `.rodata`) section is set in such a way that LMA == VMA - BASE, where *BASE* is the starting address of ROM. Non-cached `.data` section is then added at the next available LMA. -------------------------------------------------------------------------------- /common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | enable_language(C ASM) 2 | 3 | list(APPEND srcs 4 | "start.S" 5 | "vectors.S" 6 | "syscalls.c" 7 | ) 8 | 9 | add_library(common STATIC ${srcs}) 10 | target_include_directories(common PUBLIC) 11 | set_target_properties(common PROPERTIES C_STANDARD 11) 12 | target_compile_options(common PRIVATE -g -Og) 13 | target_link_libraries(common INTERFACE -nostartfiles) 14 | 15 | 16 | -------------------------------------------------------------------------------- /common/start.S: -------------------------------------------------------------------------------- 1 | .section .text.entry 2 | .type _entry, @function 3 | .global _entry 4 | _entry: 5 | .option push 6 | .option norelax 7 | la a0, _data_start 8 | la a1, _data_lma 9 | la a2, _data_size 10 | call memcpy 11 | .option pop 12 | j _start 13 | 14 | 15 | .section .text 16 | .type _start, @function 17 | .global _start 18 | _start: 19 | 20 | /* Setup the global pointer, which the ABI assumes points to the 21 | * __global_pointer$ symbol. */ 22 | .option push 23 | .option norelax 24 | la gp, __global_pointer$ 25 | .option pop 26 | 27 | /* Clear the bss segment */ 28 | la a0, _edata 29 | la a2, _end 30 | sub a2, a2, a0 31 | li a1, 0 32 | call memset 33 | 34 | /* Set MTVEC */ 35 | la t0, _vector_table 36 | ori t0, t0, 1 37 | csrrw zero, mtvec, t0 38 | 39 | /* Enable FPU */ 40 | #ifdef __riscv_flen 41 | li t0, 0x6000 42 | csrrs t0, mstatus, t0 43 | #endif 44 | 45 | /* Set up the stack pointer */ 46 | la sp, __stack_top 47 | 48 | la a0, __libc_fini_array # Register global termination functions 49 | call atexit # to be called upon exit 50 | call __libc_init_array # Run global initialization functions 51 | 52 | call syscalls_init 53 | 54 | /* Call main */ 55 | la a0, _main_argc 56 | lw a0, 0(a0) 57 | la a1, _main_argv 58 | li a2, 0 59 | call main 60 | tail exit 61 | 62 | .size _start, .-_start 63 | 64 | 65 | /* These don't have to do anything since we use init_array/fini_array. */ 66 | .global _init 67 | .type _init, @function 68 | .global _fini 69 | .type _fini, @function 70 | _init: 71 | _fini: 72 | ret 73 | 74 | .size _init, .-_init 75 | .size _fini, .-_fini 76 | 77 | /* Default arguments for 'main' */ 78 | .section .data 79 | .global _main_argc 80 | .weak _main_argc 81 | _main_argc: 82 | .word 1 83 | _argv_0: 84 | .string "test" 85 | .global _main_argv 86 | .weak _main_argv 87 | _main_argv: 88 | .word _argv_0 89 | 90 | -------------------------------------------------------------------------------- /common/syscalls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern int uart_tx_one_char(uint8_t c); 5 | 6 | ssize_t _write(int fildes, const void *buf, size_t nbyte) 7 | { 8 | const uint8_t *cbuf = (const uint8_t *) buf; 9 | for (size_t i = 0; i < nbyte; ++i) { 10 | uart_tx_one_char(cbuf[i]); 11 | } 12 | return nbyte; 13 | } 14 | 15 | void _exit(int exit_code) 16 | { 17 | while (true) { 18 | ; 19 | } 20 | } 21 | 22 | void syscalls_init(void) 23 | { 24 | } 25 | -------------------------------------------------------------------------------- /common/vectors.S: -------------------------------------------------------------------------------- 1 | /* This is the vector table. MTVEC points here. 2 | * 3 | * Use 4-byte intructions here. 1 instruction = 1 entry of the table. 4 | * The CPU jumps to MTVEC (i.e. the first entry) in case of an exception, 5 | * and (MTVEC & 0xfffffffc) + (mcause & 0x7fffffff) * 4, in case of an interrupt. 6 | */ 7 | .balign 0x100 8 | .global _vector_table 9 | .type _vector_table, @function 10 | _vector_table: 11 | .option push 12 | .option norvc 13 | j _panic_handler /* exception handler, entry 0 */ 14 | .rept 31 15 | j _interrupt_handler /* 31 identical entries, all pointing to the interrupt handler */ 16 | .endr 17 | .option pop 18 | .size _vector_table, .-_vector_table 19 | 20 | /* This should be the exception handler. 21 | * It doesn't do anything useful yet, but you can set a breakpoint here, to see if an exception happens. 22 | */ 23 | .global _panic_handler 24 | .type _panic_handler, @function 25 | _panic_handler: 26 | j _panic_handler 27 | .size _panic_handler, .-_panic_handler 28 | 29 | /* This is the interrupt handler. 30 | * It is declared as a weak function, and can be overridden. 31 | */ 32 | .global _interrupt_handler 33 | .weak _interrupt_handler 34 | .type _interrupt_handler, @function 35 | _interrupt_handler: 36 | mret 37 | .size _interrupt_handler, .-_interrupt_handler 38 | -------------------------------------------------------------------------------- /examples/blink/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | set(ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../) 4 | set(CMAKE_TOOLCHAIN_FILE ${ROOT_DIR}/toolchain-rv32.cmake) 5 | 6 | project(blink) 7 | 8 | add_executable(blink blink.c) 9 | 10 | add_subdirectory(${ROOT_DIR}/common common) 11 | add_subdirectory(${ROOT_DIR}/hal hal) 12 | 13 | target_link_libraries(blink PRIVATE common hal) 14 | 15 | target_compile_options(blink PRIVATE -g -Og) 16 | target_link_options(blink PRIVATE -g) 17 | target_compile_options(blink PRIVATE -Wall -Werror -Wextra) 18 | 19 | include(${ROOT_DIR}/utils.cmake) 20 | add_linker_scripts(blink) 21 | add_map_file(blink blink.map) 22 | make_binary(blink blink.bin) 23 | -------------------------------------------------------------------------------- /examples/blink/README.md: -------------------------------------------------------------------------------- 1 | # Blink example 2 | 3 | ## Hardware 4 | 5 | Attach an LED and a current limiting resistor between GPIO 2 and 3V3 pins of a development board. 6 | 7 | ## Building and running the example 8 | 9 | 1. Make sure you have a `riscv-none-elf-gcc` toolchain installed and added to PATH. 10 | 2. Build the example with CMake: 11 | ```bash 12 | cd examples/blink 13 | mkdir build 14 | cmake -B build -D target=esp32c3 -G Ninja . 15 | cmake --build build 16 | ``` 17 | For other chip, please use the `target=chip_name`, where `chip_name` can be any from the supported ones. 18 | You should get the following output at the end: 19 | ``` 20 | [3/4] Running utility command for blink-size 21 | text data bss dec hex filename 22 | 1844 132 177 2153 869 blink 23 | [4/4] Generating blink.bin 24 | copy from `blink' [elf32-littleriscv] to `blink.bin' [binary] 25 | ``` 26 | The following files will be generated: 27 | - `blink` — ELF output file 28 | - `blink.bin` — binary file for flashing into the chip 29 | - `blink.map` — linker map file 30 | 3. Flash the example using [esptool](https://pypi.org/project/esptool/): 31 | ```bash 32 | esptool.py --port /dev/ttyUSB0 --baud 921600 write_flash 0x0000 build/blink.bin 33 | ``` 34 | (Adjust the serial port name as needed.) 35 | 4. The LED attached to GPIO 2 should be blinking at around 3 Hz rate for ESP32-C3 (frequency can be vary depending on the maximum frequency of the selected chip). 36 | -------------------------------------------------------------------------------- /examples/blink/blink.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hal/gpio_hal.h" 3 | #include "hal/wdt_hal.h" 4 | 5 | static void delay(void); 6 | 7 | int main(void) 8 | { 9 | // Disable the watchdogs 10 | wdt_hal_context_t rwdt_ctx = RWDT_HAL_CONTEXT_DEFAULT(); 11 | wdt_hal_write_protect_disable(&rwdt_ctx); 12 | wdt_hal_disable(&rwdt_ctx); 13 | wdt_hal_set_flashboot_en(&rwdt_ctx, false); 14 | wdt_hal_context_t mwdt_ctx = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; 15 | wdt_hal_write_protect_disable(&mwdt_ctx); 16 | wdt_hal_disable(&mwdt_ctx); 17 | wdt_hal_set_flashboot_en(&mwdt_ctx, false); 18 | // Super WDT is still enabled; no HAL API for it yet 19 | 20 | // Connect an LED between 3V3 and GPIO2. 21 | // Note that the LED on ESP32-C3-DevKitM-1 is a addressable one, 22 | // so it can't be used with this example. 23 | const int gpio_num = 2; 24 | 25 | // Initialize the GPIO 26 | gpio_hal_context_t gpio_hal = { 27 | .dev = GPIO_HAL_GET_HW(GPIO_PORT_0) 28 | }; 29 | gpio_hal_func_sel(&gpio_hal, gpio_num, PIN_FUNC_GPIO); 30 | gpio_hal_output_enable(&gpio_hal, gpio_num); 31 | 32 | // Blink the LED. 33 | // Note that this example doesn't disable the watchdogs, 34 | // so the blinking will get interrupted after some time 35 | // and will continue after reset. 36 | while (1) { 37 | gpio_hal_set_level(&gpio_hal, gpio_num, 0); 38 | delay(); 39 | gpio_hal_set_level(&gpio_hal, gpio_num, 1); 40 | delay(); 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | static void delay(void) 47 | { 48 | // around 160ms, resulting in ~3Hz blink rate 49 | for (int i = 0; i < 300000; i++) { 50 | asm volatile ("nop"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/blink/gdbinit: -------------------------------------------------------------------------------- 1 | set remotetimeout 10 2 | target extended-remote | openocd -c "gdb_port pipe" -c "set ESP_RTOS none" -f "board/esp32c3-builtin.cfg" -c "init; reset halt" 3 | mon gdb_breakpoint_override hard 4 | mon flash write_image build/blink.bin 0 bin 5 | mon reset halt 6 | tb main 7 | c 8 | -------------------------------------------------------------------------------- /examples/hello_world/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | set(ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../) 4 | set(CMAKE_TOOLCHAIN_FILE ${ROOT_DIR}/toolchain-rv32.cmake) 5 | 6 | project(hello_world) 7 | 8 | add_executable(hello_world hello_world.c) 9 | 10 | add_subdirectory(${ROOT_DIR}/common common) 11 | add_subdirectory(${ROOT_DIR}/hal hal) 12 | 13 | target_link_libraries(hello_world PRIVATE common hal) 14 | 15 | target_compile_options(hello_world PRIVATE -g -Og) 16 | target_link_options(hello_world PRIVATE -g) 17 | 18 | target_compile_options(hello_world PRIVATE -Wall -Werror -Wextra) 19 | 20 | include(${ROOT_DIR}/utils.cmake) 21 | add_linker_scripts(hello_world) 22 | add_map_file(hello_world hello_world.map) 23 | make_binary(hello_world hello_world.bin) 24 | -------------------------------------------------------------------------------- /examples/hello_world/README.md: -------------------------------------------------------------------------------- 1 | # "Hello, world!" example 2 | 3 | ## Building and running the example 4 | 5 | 1. Make sure you have a `riscv-none-elf-gcc` toolchain installed and added to PATH. 6 | 2. Build the example with CMake: 7 | ```bash 8 | cd examples/hello_world 9 | mkdir build 10 | cmake -B build -D target=esp32c3 -G Ninja . 11 | cmake --build build 12 | ``` 13 | For other chip, please use the `target=chip_name`, where `chip_name` can be any from the supported ones. 14 | You should get the following output at the end: 15 | ``` 16 | [2/3] Generating hello_world.bin 17 | copy from `hello_world' [elf32-littleriscv] to `hello_world.bin' [binary] 18 | [3/3] Running utility command for hello_world-size 19 | text data bss dec hex filename 20 | 5202 132 196 5530 159a hello_world 21 | ``` 22 | The following files will be generated: 23 | - `hello_world` — ELF output file 24 | - `hello_world.bin` — binary file for flashing into the chip 25 | - `hello_world.map` — linker map file 26 | 3. Flash the example using [esptool](https://pypi.org/project/esptool/): 27 | ```bash 28 | esptool.py --port /dev/ttyUSB0 --baud 921600 write_flash 0x0000 build/hello_world.bin 29 | ``` 30 | (Adjust the serial port name as needed.) 31 | 4. See the serial output, for example using `miniterm.py` (assuming `pyserial` is installed): 32 | ```bash 33 | pyserial-miniterm /dev/ttyUSB0 115200 34 | ``` 35 | You should see the following output: 36 | ``` 37 | ESP-ROM:esp32c3-api1-20210207 38 | Build:Feb 7 2021 39 | rst:0x1 (POWERON),boot:0xc (SPI_FAST_FLASH_BOOT) 40 | Hello, world! 41 | ``` 42 | The output will keep repeating with reset reasons such as `TG0WDT_SYS_RST`, `RTCWDT_RTC_RST` — this is because this example doesn't disable or feed the hardware watchdog timers. 43 | -------------------------------------------------------------------------------- /examples/hello_world/gdbinit: -------------------------------------------------------------------------------- 1 | set remotetimeout 10 2 | target extended-remote | openocd -c "gdb_port pipe" -c "set ESP_RTOS none" -f "board/esp32c3-builtin.cfg" -c "init; reset halt" 3 | mon gdb_breakpoint_override hard 4 | mon flash write_image build/hello_world.bin 0 bin 5 | mon reset halt 6 | tb main 7 | c 8 | -------------------------------------------------------------------------------- /examples/hello_world/hello_world.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hal/wdt_hal.h" 3 | 4 | static void delay(void); 5 | 6 | int main(void) 7 | { 8 | // Disable the watchdogs 9 | wdt_hal_context_t mwdt_ctx = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; 10 | wdt_hal_write_protect_disable(&mwdt_ctx); 11 | wdt_hal_disable(&mwdt_ctx); 12 | wdt_hal_set_flashboot_en(&mwdt_ctx, false); 13 | wdt_hal_context_t rwdt_ctx = RWDT_HAL_CONTEXT_DEFAULT(); 14 | wdt_hal_write_protect_disable(&rwdt_ctx); 15 | wdt_hal_disable(&rwdt_ctx); 16 | wdt_hal_set_flashboot_en(&rwdt_ctx, false); 17 | // Super WDT is still enabled; no HAL API for it yet 18 | 19 | while(1) { 20 | printf("Hello, world!\n"); 21 | delay(); 22 | } 23 | return 0; 24 | } 25 | 26 | static void delay(void) 27 | { 28 | for (int i = 0; i < 300000; i++) { 29 | asm volatile ("nop"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /hal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | message(STATUS "Downloading esp-hal-components...") 3 | FetchContent_Declare( 4 | esp-hal-components 5 | GIT_REPOSITORY https://github.com/espressif/esp-hal-components.git 6 | GIT_TAG b4376e491dba17ee4c13e56210f880729fd99692 7 | CONFIGURE_COMMAND "" 8 | BUILD_COMMAND "" 9 | INSTALL_COMMAND "" 10 | ) 11 | FetchContent_MakeAvailable(esp-hal-components) 12 | FetchContent_GetProperties( 13 | esp-hal-components 14 | SOURCE_DIR esp_hal_components_srcdir 15 | ) 16 | message(STATUS "Downloaded esp-hal-components into ${esp_hal_components_srcdir}") 17 | 18 | set(supported_mcu esp32c3 esp32h2) 19 | if(DEFINED target AND target IN_LIST supported_mcu) 20 | message(STATUS "Configure project for ${target} ... ") 21 | else() 22 | message(FATAL_ERROR "Invalid target. \nUse argument '-D target=chip_name', where chip_name=[${supported_mcu}]") 23 | endif() 24 | 25 | # FIXME: soc component depends on sdkconfig.h 26 | string(TOUPPER ${target} target_uppercase) 27 | set(config_dir ${CMAKE_CURRENT_BINARY_DIR}/config) 28 | file(MAKE_DIRECTORY ${config_dir}) 29 | configure_file(${CMAKE_CURRENT_LIST_DIR}/sdkconfig.h.in ${config_dir}/sdkconfig.h) 30 | 31 | add_library(hal STATIC) 32 | 33 | # FIXME: CMakeLists.txt files in components/soc and components/hal are IDF-specific, 34 | # and can't be used in a normal CMake project. 35 | target_include_directories(hal PUBLIC 36 | ${esp_hal_components_srcdir}/components/soc/include 37 | ${esp_hal_components_srcdir}/components/soc/${target}/include 38 | ${esp_hal_components_srcdir}/components/hal/include 39 | ${esp_hal_components_srcdir}/components/hal/${target}/include 40 | ${esp_hal_components_srcdir}/components/hal/platform_port/include 41 | # FIXME: soc component depends on esp_common for ESP_ASSERT 42 | ${esp_hal_components_srcdir}/components/esp_common/include 43 | # FIXME: hal component depends on esp_rom due to efuse_ll.h 44 | ${esp_hal_components_srcdir}/components/esp_rom/include 45 | ${esp_hal_components_srcdir}/components/esp_rom/${target} 46 | ${config_dir} 47 | ) 48 | 49 | target_sources(hal PRIVATE 50 | ${esp_hal_components_srcdir}/components/soc/${target}/gpio_periph.c 51 | ${esp_hal_components_srcdir}/components/hal/gpio_hal.c 52 | ${esp_hal_components_srcdir}/components/hal/wdt_hal_iram.c 53 | ) 54 | 55 | # FIXME: hal component can't be compiled with -Wall -Wextra -Werror: 56 | target_compile_options(hal PUBLIC -Wno-unused-parameter) 57 | 58 | # Add the linker script for peripheral objects 59 | target_link_options(hal PUBLIC -T ${esp_hal_components_srcdir}/components/soc/${target}/ld/${target}.peripherals.ld) 60 | 61 | -------------------------------------------------------------------------------- /hal/README.md: -------------------------------------------------------------------------------- 1 | This component provides a HAL for functions such as: 2 | * GPIO 3 | * WDT 4 | 5 | So that we don't have to implement the HAL from scratch, the source from https://github.com/espressif/esp-hal-components/tree/sync-3-master is used. Since the upstream CMakeLists.txt files can't yet be used a normal CMake library, the [CMakeLists.txt](CMakeLists.txt) of this component manually adds the right set of include directories and source files to the build. 6 | 7 | Note: this is done just for demonstration purposes, to be used in the examples. This component isn't intended to provide the HAL for all peripherals and all chips. 8 | -------------------------------------------------------------------------------- /hal/sdkconfig.h.in: -------------------------------------------------------------------------------- 1 | #define CONFIG_IDF_TARGET_${target_uppercase} 1 2 | -------------------------------------------------------------------------------- /img/esp32c3-directboot.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | Magic 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | _entry 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | .text 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | .rodata 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | unused 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | RAM 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | IROM 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | DROM 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | Magic 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | _entry 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | .text 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | .rodata 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | .data 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | Magic 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | _entry 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | .text 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | .rodata 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | .data 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | .data 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | .bss 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | Stack 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | Flash address space 247 | 248 | 249 | 250 | 251 | 252 | 253 | CPU address space 254 | 255 | 256 | 257 | 258 | 259 | 260 | 0x0 261 | 262 | 263 | 264 | 265 | 266 | 267 | 0x8 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | .data 276 | 277 | 278 | 279 | 280 | 281 | 282 | 4MB 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | unused 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | unused 299 | 300 | 301 | 302 | 303 | 304 | 305 | 0x3C000000 306 | 307 | 308 | 309 | 310 | 311 | 312 | 0x3C400000 313 | 314 | 315 | 316 | 317 | 318 | 319 | 0x3FC80000 320 | 321 | 322 | 323 | 324 | 325 | 326 | 0x3FCD0000 327 | 328 | 329 | 330 | 331 | 332 | 333 | 0x42000000 334 | 335 | 336 | 337 | 338 | 339 | 340 | 0x42400000 341 | 342 | 343 | 344 | 345 | 346 | 347 | Mapped 348 | 349 | using 350 | 351 | data 352 | 353 | cache 354 | 355 | 356 | 357 | 358 | 359 | 360 | Mapped 361 | 362 | using 363 | 364 | instruction 365 | 366 | cache 367 | 368 | 369 | 370 | 371 | 372 | 373 | .data section 374 | 375 | copied at 376 | 377 | startup 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | -------------------------------------------------------------------------------- /img/esp32h2-directboot.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ld/esp32c3/common.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | .header : AT(0) 6 | { 7 | _irom_start = .; 8 | LONG(0xaedb041d) 9 | LONG(0xaedb041d) 10 | } > irom 11 | 12 | .text.entry ORIGIN(irom) + 8 : 13 | { 14 | KEEP(*(.text.entry)) 15 | } > irom 16 | 17 | .text : 18 | { 19 | *(.text .stub .text.* .gnu.linkonce.t.*) 20 | *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) 21 | *(.gnu.warning) 22 | } 23 | . = ALIGN(4); 24 | PROVIDE (__etext = .); 25 | PROVIDE (_etext = .); 26 | PROVIDE (etext = .); 27 | _irom_size = . - _irom_start; 28 | 29 | _drom_start = ORIGIN(drom) + _irom_size; 30 | .rodata _drom_start : AT(_irom_size) 31 | { 32 | *(.rodata .rodata.* .srodata .srodata.* .sdata2 .sdata2.* .gnu.linkonce.r.*) 33 | *(.rela.data .rela.data.* .rela.gnu.linkonce.r.*) 34 | } > drom 35 | 36 | .rodata1 : 37 | { 38 | *(.rodata1) 39 | } > drom 40 | 41 | .init_array : 42 | { 43 | PROVIDE_HIDDEN (__init_array_start = .); 44 | KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) 45 | KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) 46 | PROVIDE_HIDDEN (__init_array_end = .); 47 | } > drom 48 | 49 | .fini_array : 50 | { 51 | PROVIDE_HIDDEN (__fini_array_start = .); 52 | KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) 53 | KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) 54 | PROVIDE_HIDDEN (__fini_array_end = .); 55 | } > drom 56 | 57 | .ctors : 58 | { 59 | KEEP (*crtbegin.o(.ctors)) 60 | KEEP (*crtbegin?.o(.ctors)) 61 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) 62 | KEEP (*(SORT(.ctors.*))) 63 | KEEP (*(.ctors)) 64 | } > drom 65 | 66 | .dtors : 67 | { 68 | KEEP (*crtbegin.o(.dtors)) 69 | KEEP (*crtbegin?.o(.dtors)) 70 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) 71 | KEEP (*(SORT(.dtors.*))) 72 | KEEP (*(.dtors)) 73 | } > drom 74 | 75 | _drom_size = . - _drom_start; 76 | 77 | .data ORIGIN(ram) : AT(_irom_size + _drom_size) 78 | { 79 | _data_start = .; 80 | __DATA_BEGIN__ = .; 81 | *(.data .data.* .gnu.linkonce.d.*) 82 | *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) 83 | SORT(CONSTRUCTORS) 84 | } > ram 85 | .data1 : 86 | { 87 | *(.data1) 88 | } 89 | .sdata : 90 | { 91 | __SDATA_BEGIN__ = .; 92 | *(.sdata .sdata.* .gnu.linkonce.s.*) 93 | } 94 | . = ALIGN(4); 95 | _edata = .; PROVIDE (edata = .); 96 | _data_lma = ORIGIN(drom) + LOADADDR(.data); 97 | _data_size = _edata - _data_start; 98 | 99 | __bss_start = .; 100 | .sbss : 101 | { 102 | *(.dynsbss) 103 | *(.sbss .sbss.* .gnu.linkonce.sb.*) 104 | *(.scommon) 105 | } 106 | .bss : 107 | { 108 | *(.dynbss) 109 | *(.bss .bss.* .gnu.linkonce.b.*) 110 | *(COMMON) 111 | } 112 | . = ALIGN(4); 113 | __BSS_END__ = .; 114 | __global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, 115 | MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800)); 116 | _end = .; PROVIDE (end = .); 117 | 118 | /* Stack */ 119 | .stack : 120 | { 121 | __stack_bottom = .; 122 | __stack_top = ORIGIN(ram) + LENGTH(ram); 123 | __stack_size_min = 0x4000; 124 | ASSERT(__stack_bottom + __stack_size_min < __stack_top, "Error: no space for stack"); 125 | } 126 | 127 | /* Stabs debugging sections. */ 128 | .stab 0 : { *(.stab) } 129 | .stabstr 0 : { *(.stabstr) } 130 | .stab.excl 0 : { *(.stab.excl) } 131 | .stab.exclstr 0 : { *(.stab.exclstr) } 132 | .stab.index 0 : { *(.stab.index) } 133 | .stab.indexstr 0 : { *(.stab.indexstr) } 134 | .comment 0 : { *(.comment) } 135 | .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } 136 | /* DWARF debug sections. 137 | Symbols in the DWARF debugging sections are relative to the beginning 138 | of the section so we begin them at 0. */ 139 | /* DWARF 1 */ 140 | .debug 0 : { *(.debug) } 141 | .line 0 : { *(.line) } 142 | /* GNU DWARF 1 extensions */ 143 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 144 | .debug_sfnames 0 : { *(.debug_sfnames) } 145 | /* DWARF 1.1 and DWARF 2 */ 146 | .debug_aranges 0 : { *(.debug_aranges) } 147 | .debug_pubnames 0 : { *(.debug_pubnames) } 148 | /* DWARF 2 */ 149 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 150 | .debug_abbrev 0 : { *(.debug_abbrev) } 151 | .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } 152 | .debug_frame 0 : { *(.debug_frame) } 153 | .debug_str 0 : { *(.debug_str) } 154 | .debug_loc 0 : { *(.debug_loc) } 155 | .debug_macinfo 0 : { *(.debug_macinfo) } 156 | /* SGI/MIPS DWARF 2 extensions */ 157 | .debug_weaknames 0 : { *(.debug_weaknames) } 158 | .debug_funcnames 0 : { *(.debug_funcnames) } 159 | .debug_typenames 0 : { *(.debug_typenames) } 160 | .debug_varnames 0 : { *(.debug_varnames) } 161 | /* DWARF 3 */ 162 | .debug_pubtypes 0 : { *(.debug_pubtypes) } 163 | .debug_ranges 0 : { *(.debug_ranges) } 164 | /* DWARF Extension. */ 165 | .debug_macro 0 : { *(.debug_macro) } 166 | .debug_addr 0 : { *(.debug_addr) } 167 | .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } 168 | /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } 169 | } 170 | -------------------------------------------------------------------------------- /ld/esp32c3/memory.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | irom (x): org = 0x42000000, len = 0x400000 4 | drom (r): org = 0x3C000000, len = 0x400000 5 | ram (rw): org = 0x3FC80000, len = 0x50000 6 | rtc_ram (rx): org = 0x50000000, len = 0x2000 7 | } 8 | -------------------------------------------------------------------------------- /ld/esp32c3/romfuncs.ld: -------------------------------------------------------------------------------- 1 | /* ROM function interface esp32c3.rom.libgcc.ld for esp32c3 2 | * 3 | * 4 | * Generated from ./interface-esp32c3.yml md5sum 93b28a9e1fe42d212018eb4336849208 5 | * 6 | * Compatible with ROM where ECO version equal or greater to 0. 7 | */ 8 | 9 | /*************************************** 10 | Group libgcc 11 | ***************************************/ 12 | 13 | /* Functions */ 14 | __absvdi2 = 0x40000764; 15 | __absvsi2 = 0x40000768; 16 | __adddf3 = 0x4000076c; 17 | __addsf3 = 0x40000770; 18 | __addvdi3 = 0x40000774; 19 | __addvsi3 = 0x40000778; 20 | __ashldi3 = 0x4000077c; 21 | __ashrdi3 = 0x40000780; 22 | __bswapdi2 = 0x40000784; 23 | __bswapsi2 = 0x40000788; 24 | __clear_cache = 0x4000078c; 25 | __clrsbdi2 = 0x40000790; 26 | __clrsbsi2 = 0x40000794; 27 | __clzdi2 = 0x40000798; 28 | __clzsi2 = 0x4000079c; 29 | __cmpdi2 = 0x400007a0; 30 | __ctzdi2 = 0x400007a4; 31 | __ctzsi2 = 0x400007a8; 32 | __divdc3 = 0x400007ac; 33 | __divdf3 = 0x400007b0; 34 | __divdi3 = 0x400007b4; 35 | __divsc3 = 0x400007b8; 36 | __divsf3 = 0x400007bc; 37 | __divsi3 = 0x400007c0; 38 | __eqdf2 = 0x400007c4; 39 | __eqsf2 = 0x400007c8; 40 | __extendsfdf2 = 0x400007cc; 41 | __ffsdi2 = 0x400007d0; 42 | __ffssi2 = 0x400007d4; 43 | __fixdfdi = 0x400007d8; 44 | __fixdfsi = 0x400007dc; 45 | __fixsfdi = 0x400007e0; 46 | __fixsfsi = 0x400007e4; 47 | __fixunsdfsi = 0x400007e8; 48 | __fixunssfdi = 0x400007ec; 49 | __fixunssfsi = 0x400007f0; 50 | __floatdidf = 0x400007f4; 51 | __floatdisf = 0x400007f8; 52 | __floatsidf = 0x400007fc; 53 | __floatsisf = 0x40000800; 54 | __floatundidf = 0x40000804; 55 | __floatundisf = 0x40000808; 56 | __floatunsidf = 0x4000080c; 57 | __floatunsisf = 0x40000810; 58 | __gcc_bcmp = 0x40000814; 59 | __gedf2 = 0x40000818; 60 | __gesf2 = 0x4000081c; 61 | __gtdf2 = 0x40000820; 62 | __gtsf2 = 0x40000824; 63 | __ledf2 = 0x40000828; 64 | __lesf2 = 0x4000082c; 65 | __lshrdi3 = 0x40000830; 66 | __ltdf2 = 0x40000834; 67 | __ltsf2 = 0x40000838; 68 | __moddi3 = 0x4000083c; 69 | __modsi3 = 0x40000840; 70 | __muldc3 = 0x40000844; 71 | __muldf3 = 0x40000848; 72 | __muldi3 = 0x4000084c; 73 | __mulsc3 = 0x40000850; 74 | __mulsf3 = 0x40000854; 75 | __mulsi3 = 0x40000858; 76 | __mulvdi3 = 0x4000085c; 77 | __mulvsi3 = 0x40000860; 78 | __nedf2 = 0x40000864; 79 | __negdf2 = 0x40000868; 80 | __negdi2 = 0x4000086c; 81 | __negsf2 = 0x40000870; 82 | __negvdi2 = 0x40000874; 83 | __negvsi2 = 0x40000878; 84 | __nesf2 = 0x4000087c; 85 | __paritysi2 = 0x40000880; 86 | __popcountdi2 = 0x40000884; 87 | __popcountsi2 = 0x40000888; 88 | __powidf2 = 0x4000088c; 89 | __powisf2 = 0x40000890; 90 | __subdf3 = 0x40000894; 91 | __subsf3 = 0x40000898; 92 | __subvdi3 = 0x4000089c; 93 | __subvsi3 = 0x400008a0; 94 | __truncdfsf2 = 0x400008a4; 95 | __ucmpdi2 = 0x400008a8; 96 | __udivdi3 = 0x400008ac; 97 | __udivmoddi4 = 0x400008b0; 98 | __udivsi3 = 0x400008b4; 99 | __udiv_w_sdiv = 0x400008b8; 100 | __umoddi3 = 0x400008bc; 101 | __umodsi3 = 0x400008c0; 102 | __unorddf2 = 0x400008c4; 103 | __unordsf2 = 0x400008c8; 104 | 105 | 106 | /*************************************** 107 | Group newlib 108 | ***************************************/ 109 | 110 | /* Functions */ 111 | memset = 0x40000354; 112 | memcpy = 0x40000358; 113 | memmove = 0x4000035c; 114 | memcmp = 0x40000360; 115 | strcpy = 0x40000364; 116 | strncpy = 0x40000368; 117 | strcmp = 0x4000036c; 118 | strncmp = 0x40000370; 119 | strlen = 0x40000374; 120 | strstr = 0x40000378; 121 | bzero = 0x4000037c; 122 | isalnum = 0x40000388; 123 | isalpha = 0x4000038c; 124 | isascii = 0x40000390; 125 | isblank = 0x40000394; 126 | iscntrl = 0x40000398; 127 | isdigit = 0x4000039c; 128 | islower = 0x400003a0; 129 | isgraph = 0x400003a4; 130 | isprint = 0x400003a8; 131 | ispunct = 0x400003ac; 132 | isspace = 0x400003b0; 133 | isupper = 0x400003b4; 134 | toupper = 0x400003b8; 135 | tolower = 0x400003bc; 136 | toascii = 0x400003c0; 137 | memccpy = 0x400003c4; 138 | memchr = 0x400003c8; 139 | memrchr = 0x400003cc; 140 | strcasecmp = 0x400003d0; 141 | strcasestr = 0x400003d4; 142 | strcat = 0x400003d8; 143 | strdup = 0x400003dc; 144 | strchr = 0x400003e0; 145 | strcspn = 0x400003e4; 146 | strcoll = 0x400003e8; 147 | strlcat = 0x400003ec; 148 | strlcpy = 0x400003f0; 149 | strlwr = 0x400003f4; 150 | strncasecmp = 0x400003f8; 151 | strncat = 0x400003fc; 152 | strndup = 0x40000400; 153 | strnlen = 0x40000404; 154 | strrchr = 0x40000408; 155 | strsep = 0x4000040c; 156 | strspn = 0x40000410; 157 | strtok_r = 0x40000414; 158 | strupr = 0x40000418; 159 | longjmp = 0x4000041c; 160 | setjmp = 0x40000420; 161 | abs = 0x40000424; 162 | div = 0x40000428; 163 | labs = 0x4000042c; 164 | ldiv = 0x40000430; 165 | qsort = 0x40000434; 166 | rand_r = 0x40000438; 167 | rand = 0x4000043c; 168 | srand = 0x40000440; 169 | utoa = 0x40000444; 170 | itoa = 0x40000448; 171 | atoi = 0x4000044c; 172 | atol = 0x40000450; 173 | strtol = 0x40000454; 174 | strtoul = 0x40000458; 175 | 176 | uart_tx_one_char = 0x40000068; 177 | -------------------------------------------------------------------------------- /ld/esp32h2/common.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | .header : AT(0) 6 | { 7 | _rom_start = .; 8 | LONG(0xaedb041d) 9 | LONG(0xaedb041d) 10 | } > rom 11 | 12 | .text.entry ORIGIN(rom) + 8 : 13 | { 14 | KEEP(*(.text.entry)) 15 | } > rom 16 | 17 | .text : 18 | { 19 | *(.text .stub .text.* .gnu.linkonce.t.*) 20 | *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) 21 | *(.gnu.warning) 22 | } 23 | . = ALIGN(4); 24 | 25 | .rodata : 26 | { 27 | *(.rodata .rodata1 .rodata.* .srodata .srodata.* .sdata2 .sdata2.* .gnu.linkonce.r.*) 28 | *(.rela.data .rela.data.* .rela.gnu.linkonce.r.*) 29 | } > rom 30 | 31 | .init_array : 32 | { 33 | PROVIDE_HIDDEN (__init_array_start = .); 34 | KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) 35 | KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) 36 | PROVIDE_HIDDEN (__init_array_end = .); 37 | } > rom 38 | 39 | .fini_array : 40 | { 41 | PROVIDE_HIDDEN (__fini_array_start = .); 42 | KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) 43 | KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) 44 | PROVIDE_HIDDEN (__fini_array_end = .); 45 | } > rom 46 | 47 | .ctors : 48 | { 49 | KEEP (*crtbegin.o(.ctors)) 50 | KEEP (*crtbegin?.o(.ctors)) 51 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) 52 | KEEP (*(SORT(.ctors.*))) 53 | KEEP (*(.ctors)) 54 | } > rom 55 | 56 | .dtors : 57 | { 58 | KEEP (*crtbegin.o(.dtors)) 59 | KEEP (*crtbegin?.o(.dtors)) 60 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) 61 | KEEP (*(SORT(.dtors.*))) 62 | KEEP (*(.dtors)) 63 | } > rom 64 | 65 | PROVIDE (__etext = .); 66 | PROVIDE (_etext = .); 67 | PROVIDE (etext = .); 68 | _rom_size = . - _rom_start; 69 | 70 | .data ORIGIN(ram) : AT(_rom_size) 71 | { 72 | _data_start = .; 73 | __DATA_BEGIN__ = .; 74 | *(.data .data.* .gnu.linkonce.d.*) 75 | *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) 76 | SORT(CONSTRUCTORS) 77 | } > ram 78 | .data1 : 79 | { 80 | *(.data1) 81 | } 82 | .sdata : 83 | { 84 | __SDATA_BEGIN__ = .; 85 | *(.sdata .sdata.* .gnu.linkonce.s.*) 86 | } 87 | . = ALIGN(4); 88 | _edata = .; PROVIDE (edata = .); 89 | _data_lma = ORIGIN(rom) + LOADADDR(.data); 90 | _data_size = _edata - _data_start; 91 | 92 | __bss_start = .; 93 | .sbss : 94 | { 95 | *(.dynsbss) 96 | *(.sbss .sbss.* .gnu.linkonce.sb.*) 97 | *(.scommon) 98 | } 99 | .bss : 100 | { 101 | *(.dynbss) 102 | *(.bss .bss.* .gnu.linkonce.b.*) 103 | *(COMMON) 104 | } 105 | . = ALIGN(4); 106 | __BSS_END__ = .; 107 | __global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, 108 | MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800)); 109 | _end = .; PROVIDE (end = .); 110 | 111 | /* Stack */ 112 | .stack : 113 | { 114 | __stack_bottom = .; 115 | __stack_top = ORIGIN(ram) + LENGTH(ram); 116 | __stack_size_min = 0x4000; 117 | ASSERT(__stack_bottom + __stack_size_min < __stack_top, "Error: no space for stack"); 118 | } 119 | 120 | /* Stabs debugging sections. */ 121 | .stab 0 : { *(.stab) } 122 | .stabstr 0 : { *(.stabstr) } 123 | .stab.excl 0 : { *(.stab.excl) } 124 | .stab.exclstr 0 : { *(.stab.exclstr) } 125 | .stab.index 0 : { *(.stab.index) } 126 | .stab.indexstr 0 : { *(.stab.indexstr) } 127 | .comment 0 : { *(.comment) } 128 | .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } 129 | /* DWARF debug sections. 130 | Symbols in the DWARF debugging sections are relative to the beginning 131 | of the section so we begin them at 0. */ 132 | /* DWARF 1 */ 133 | .debug 0 : { *(.debug) } 134 | .line 0 : { *(.line) } 135 | /* GNU DWARF 1 extensions */ 136 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 137 | .debug_sfnames 0 : { *(.debug_sfnames) } 138 | /* DWARF 1.1 and DWARF 2 */ 139 | .debug_aranges 0 : { *(.debug_aranges) } 140 | .debug_pubnames 0 : { *(.debug_pubnames) } 141 | /* DWARF 2 */ 142 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 143 | .debug_abbrev 0 : { *(.debug_abbrev) } 144 | .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } 145 | .debug_frame 0 : { *(.debug_frame) } 146 | .debug_str 0 : { *(.debug_str) } 147 | .debug_loc 0 : { *(.debug_loc) } 148 | .debug_macinfo 0 : { *(.debug_macinfo) } 149 | /* SGI/MIPS DWARF 2 extensions */ 150 | .debug_weaknames 0 : { *(.debug_weaknames) } 151 | .debug_funcnames 0 : { *(.debug_funcnames) } 152 | .debug_typenames 0 : { *(.debug_typenames) } 153 | .debug_varnames 0 : { *(.debug_varnames) } 154 | /* DWARF 3 */ 155 | .debug_pubtypes 0 : { *(.debug_pubtypes) } 156 | .debug_ranges 0 : { *(.debug_ranges) } 157 | /* DWARF Extension. */ 158 | .debug_macro 0 : { *(.debug_macro) } 159 | .debug_addr 0 : { *(.debug_addr) } 160 | .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } 161 | /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } 162 | } 163 | -------------------------------------------------------------------------------- /ld/esp32h2/memory.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | rom (rx): org = 0x42000000, len = 0x400000 4 | ram (rw): org = 0x40800000, len = 0x40000 5 | lp_ram (rw): org = 0x50000000, len = 0x1000 6 | } -------------------------------------------------------------------------------- /ld/esp32h2/romfuncs.ld: -------------------------------------------------------------------------------- 1 | /* ROM function interface esp32h2.rom.ld for esp32h2 2 | * 3 | * 4 | * Generated from ./interface-esp32h2.yml md5sum c0ad4e113e5b29bb9d799f10f03edbc1 5 | * 6 | * Compatible with ROM where ECO version equal or greater to 0. 7 | */ 8 | 9 | /*************************************** 10 | Group libgcc 11 | ***************************************/ 12 | 13 | /* Functions */ 14 | __absvdi2 = 0x40000850; 15 | __absvsi2 = 0x40000854; 16 | __adddf3 = 0x40000858; 17 | __addsf3 = 0x4000085c; 18 | __addvdi3 = 0x40000860; 19 | __addvsi3 = 0x40000864; 20 | __ashldi3 = 0x40000868; 21 | __ashrdi3 = 0x4000086c; 22 | __bswapdi2 = 0x40000870; 23 | __bswapsi2 = 0x40000874; 24 | __clear_cache = 0x40000878; 25 | __clrsbdi2 = 0x4000087c; 26 | __clrsbsi2 = 0x40000880; 27 | __clzdi2 = 0x40000884; 28 | __clzsi2 = 0x40000888; 29 | __cmpdi2 = 0x4000088c; 30 | __ctzdi2 = 0x40000890; 31 | __ctzsi2 = 0x40000894; 32 | __divdc3 = 0x40000898; 33 | __divdf3 = 0x4000089c; 34 | __divdi3 = 0x400008a0; 35 | __divsc3 = 0x400008a4; 36 | __divsf3 = 0x400008a8; 37 | __divsi3 = 0x400008ac; 38 | __eqdf2 = 0x400008b0; 39 | __eqsf2 = 0x400008b4; 40 | __extendsfdf2 = 0x400008b8; 41 | __ffsdi2 = 0x400008bc; 42 | __ffssi2 = 0x400008c0; 43 | __fixdfdi = 0x400008c4; 44 | __fixdfsi = 0x400008c8; 45 | __fixsfdi = 0x400008cc; 46 | __fixsfsi = 0x400008d0; 47 | __fixunsdfsi = 0x400008d4; 48 | __fixunssfdi = 0x400008d8; 49 | __fixunssfsi = 0x400008dc; 50 | __floatdidf = 0x400008e0; 51 | __floatdisf = 0x400008e4; 52 | __floatsidf = 0x400008e8; 53 | __floatsisf = 0x400008ec; 54 | __floatundidf = 0x400008f0; 55 | __floatundisf = 0x400008f4; 56 | __floatunsidf = 0x400008f8; 57 | __floatunsisf = 0x400008fc; 58 | __gcc_bcmp = 0x40000900; 59 | __gedf2 = 0x40000904; 60 | __gesf2 = 0x40000908; 61 | __gtdf2 = 0x4000090c; 62 | __gtsf2 = 0x40000910; 63 | __ledf2 = 0x40000914; 64 | __lesf2 = 0x40000918; 65 | __lshrdi3 = 0x4000091c; 66 | __ltdf2 = 0x40000920; 67 | __ltsf2 = 0x40000924; 68 | __moddi3 = 0x40000928; 69 | __modsi3 = 0x4000092c; 70 | __muldc3 = 0x40000930; 71 | __muldf3 = 0x40000934; 72 | __muldi3 = 0x40000938; 73 | __mulsc3 = 0x4000093c; 74 | __mulsf3 = 0x40000940; 75 | __mulsi3 = 0x40000944; 76 | __mulvdi3 = 0x40000948; 77 | __mulvsi3 = 0x4000094c; 78 | __nedf2 = 0x40000950; 79 | __negdf2 = 0x40000954; 80 | __negdi2 = 0x40000958; 81 | __negsf2 = 0x4000095c; 82 | __negvdi2 = 0x40000960; 83 | __negvsi2 = 0x40000964; 84 | __nesf2 = 0x40000968; 85 | __paritysi2 = 0x4000096c; 86 | __popcountdi2 = 0x40000970; 87 | __popcountsi2 = 0x40000974; 88 | __powidf2 = 0x40000978; 89 | __powisf2 = 0x4000097c; 90 | __subdf3 = 0x40000980; 91 | __subsf3 = 0x40000984; 92 | __subvdi3 = 0x40000988; 93 | __subvsi3 = 0x4000098c; 94 | __truncdfsf2 = 0x40000990; 95 | __ucmpdi2 = 0x40000994; 96 | __udivdi3 = 0x40000998; 97 | __udivmoddi4 = 0x4000099c; 98 | __udivsi3 = 0x400009a0; 99 | __udiv_w_sdiv = 0x400009a4; 100 | __umoddi3 = 0x400009a8; 101 | __umodsi3 = 0x400009ac; 102 | __unorddf2 = 0x400009b0; 103 | __unordsf2 = 0x400009b4; 104 | __extenddftf2 = 0x400009b8; 105 | __trunctfdf2 = 0x400009bc; 106 | 107 | 108 | /*************************************** 109 | Group newlib 110 | ***************************************/ 111 | 112 | /* Functions */ 113 | esp_rom_newlib_init_common_mutexes = 0x4000049c; 114 | memset = 0x400004a0; 115 | memcpy = 0x400004a4; 116 | memmove = 0x400004a8; 117 | memcmp = 0x400004ac; 118 | strcpy = 0x400004b0; 119 | strncpy = 0x400004b4; 120 | strcmp = 0x400004b8; 121 | strncmp = 0x400004bc; 122 | strlen = 0x400004c0; 123 | strstr = 0x400004c4; 124 | bzero = 0x400004c8; 125 | _isatty_r = 0x400004cc; 126 | sbrk = 0x400004d0; 127 | isalnum = 0x400004d4; 128 | isalpha = 0x400004d8; 129 | isascii = 0x400004dc; 130 | isblank = 0x400004e0; 131 | iscntrl = 0x400004e4; 132 | isdigit = 0x400004e8; 133 | islower = 0x400004ec; 134 | isgraph = 0x400004f0; 135 | isprint = 0x400004f4; 136 | ispunct = 0x400004f8; 137 | isspace = 0x400004fc; 138 | isupper = 0x40000500; 139 | toupper = 0x40000504; 140 | tolower = 0x40000508; 141 | toascii = 0x4000050c; 142 | memccpy = 0x40000510; 143 | memchr = 0x40000514; 144 | memrchr = 0x40000518; 145 | strcasecmp = 0x4000051c; 146 | strcasestr = 0x40000520; 147 | strcat = 0x40000524; 148 | strdup = 0x40000528; 149 | strchr = 0x4000052c; 150 | strcspn = 0x40000530; 151 | strcoll = 0x40000534; 152 | strlcat = 0x40000538; 153 | strlcpy = 0x4000053c; 154 | strlwr = 0x40000540; 155 | strncasecmp = 0x40000544; 156 | strncat = 0x40000548; 157 | strndup = 0x4000054c; 158 | strnlen = 0x40000550; 159 | strrchr = 0x40000554; 160 | strsep = 0x40000558; 161 | strspn = 0x4000055c; 162 | strtok_r = 0x40000560; 163 | strupr = 0x40000564; 164 | longjmp = 0x40000568; 165 | setjmp = 0x4000056c; 166 | abs = 0x40000570; 167 | div = 0x40000574; 168 | labs = 0x40000578; 169 | ldiv = 0x4000057c; 170 | qsort = 0x40000580; 171 | rand_r = 0x40000584; 172 | rand = 0x40000588; 173 | srand = 0x4000058c; 174 | utoa = 0x40000590; 175 | itoa = 0x40000594; 176 | atoi = 0x40000598; 177 | atol = 0x4000059c; 178 | strtol = 0x400005a0; 179 | strtoul = 0x400005a4; 180 | 181 | uart_tx_one_char = 0x40000058; 182 | -------------------------------------------------------------------------------- /toolchain-rv32.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Generic) 2 | 3 | set(CMAKE_C_COMPILER riscv-none-elf-gcc) 4 | set(CMAKE_CXX_COMPILER riscv-none-elf-g++) 5 | set(CMAKE_ASM_COMPILER riscv-none-elf-gcc) 6 | set(CMAKE_OBJCOPY riscv-none-elf-objcopy) 7 | 8 | set(riscv_arch_flag "-march=rv32imc_zicsr") 9 | 10 | set(CMAKE_C_FLAGS ${riscv_arch_flag} CACHE STRING "C Compiler Base Flags") 11 | set(CMAKE_CXX_FLAGS ${riscv_arch_flag} CACHE STRING "C++ Compiler Base Flags") 12 | set(CMAKE_ASM_FLAGS ${riscv_arch_flag} CACHE STRING "Assembler Base Flags") 13 | set(CMAKE_EXE_LINKER_FLAGS "${riscv_arch_flag} --specs=nano.specs --specs=nosys.specs" CACHE STRING "Linker Base Flags") 14 | -------------------------------------------------------------------------------- /utils.cmake: -------------------------------------------------------------------------------- 1 | set(LD_DIR "${CMAKE_CURRENT_LIST_DIR}/ld/${target}") 2 | 3 | function(__add_linker_script_and_dep target ldscript) 4 | set(ldscript_path ${LD_DIR}/${ldscript}) 5 | target_link_libraries(${target} PRIVATE -T ${ldscript_path}) 6 | set_target_properties(${target} PROPERTIES LINK_DEPENDS ${ldscript_path}) 7 | endfunction() 8 | 9 | function(add_linker_scripts target) 10 | __add_linker_script_and_dep(${target} memory.ld) 11 | __add_linker_script_and_dep(${target} common.ld) 12 | __add_linker_script_and_dep(${target} romfuncs.ld) 13 | endfunction() 14 | 15 | function(add_map_file target filename) 16 | set(mapfile "${CMAKE_BINARY_DIR}/${filename}") 17 | target_link_libraries(${target} PRIVATE "-Wl,--Map=${mapfile}") 18 | endfunction() 19 | 20 | function(make_binary elf_target filename) 21 | add_custom_target(${elf_target}-size ALL DEPENDS ${elf_target}) 22 | add_custom_command(TARGET ${elf_target}-size POST_BUILD COMMAND riscv-none-elf-size ${elf_target}) 23 | 24 | add_custom_target(${filename}-binary ALL DEPENDS ${filename}) 25 | add_custom_command(OUTPUT ${filename} 26 | COMMAND ${CMAKE_OBJCOPY} 27 | ARGS -v -O binary ${elf_target} ${CMAKE_BINARY_DIR}/${filename} 28 | DEPENDS ${elf_target}) 29 | endfunction() 30 | --------------------------------------------------------------------------------