Программирование ARM ESP32: как сгенерировать код ассемблера из кода C Thu, April 25 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

ESP32: как сгенерировать код ассемблера из кода C Печать
Добавил(а) microsin   

Компилятор riscv32-esp-elf-gcc умеет генерировать ассемблера, если указать ему опцию -S. Однако в реальном проекте кроме опции -S компилятору нужно указать еще много чего - где искать заголовочные файлы, указать тип кристалла, тип оптимизации и т. п.

Предположим, что Вы хотите оптимизировать какой-нибудь обработчик прерывания путем правки его кода на ассемблере. Для этой цели надо из кода C получить код ассемблера. Как это сделать, процесс по шагам:

1. Создайте для оптимизируемого кода отдельный модуль на языке C. Уберите из него по максимуму все лишнее, чтобы потом было проще разобраться. Добейтесь, чтобы этот модуль нормально компилировался в составе проекта.

2. Внесите в этот модуль специально какую-либо ошибку. Это можно сделать с помощью директивы #error, например:

#include "esp_attr.h"
#include "driver/timer.h"
#include "driver/ledc.h"
#include "soundISR.h"
#include "pins.h"
 
volatile TPlayState soundmode = PLAY_IDLE;
volatile int32_t wavidx;
int32_t wavlength;
uint8_t *pstart;
 
static void pwmduty(uint8_t v8)
{
  ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, v8);
  ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);
}
 
/* Обработчик прерывания таймера */
void IRAM_ATTR timer0_ISR(void *ptr)
{
#error This is dummy error.
TESTLED(1);
  *(uint32_t*)(TIMG_INT_CLR_TIMERS_REG(TIMER_GROUP)) = 1;
  *(uint32_t*)(TIMG_T0CONFIG_REG(TIMER_GROUP)) |= TIMG_T0_ALARM_EN;
  if (PLAY_FILE != soundmode)
     return;
  if(wavidx < wavlength)
  {
    pwmduty(pstart[wavidx]);
    wavidx++;
  }
  else
  {
    soundmode = PLAY_IDLE;
  }
TESTLED(0);
}

3. Скомпилируйте проект. Компилятор увидит ошибку, и вместе с выводом ошибки выдаст полную командную строку, с которой модуль компилировался. Например, если компилируется модуль soundISR.c, то получится вывод наподобие следующего:

/home/имяпользователя/.espressif/tools/riscv32-esp-elf/esp-2021r2-patch3-8.4.0/riscv32-esp-elf/bin/riscv32-esp-elf-gcc
 -DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\" -Iconfig -I/home/имяпользователя/каталогпроекта
 -I/home/имяпользователя/каталогпроекта/include -I/home/имяпользователя/esp/esp-idf/components/newlib/platform_include
 -I/home/имяпользователя/esp/esp-idf/components/freertos/include/esp_additions/freertos
 -I/home/имяпользователя/esp/esp-idf/components/freertos/include
 .. другие пути поиска подключаемых файлов ..
 -march=rv32imc -ffunction-sections -fdata-sections
 -Wall -Werror=all -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wextra
 -Wno-unused-parameter -Wno-sign-compare -ggdb -Wno-error=format= -nostartfiles -Wno-format
 -O2
 -fmacro-prefix-map=/home/имяпользователя/каталогпроекта=.
 -fmacro-prefix-map=/home/имяпользователя/esp/esp-idf=IDF -fstrict-volatile-bitfields
 -Wno-error=unused-but-set-variable -fno-jump-tables -fno-tree-switch-conversion
 -std=gnu99 -Wno-old-style-declaration -D_GNU_SOURCE -DIDF_VER=\"v4.4.1-dirty\"
 -DESP_PLATFORM -D_POSIX_READER_WRITER_LOCKS -MD -MT esp-idf/espidf/CMakeFiles/__idf_espidf.dir/__/src/soundISR.c.obj
 -MF esp-idf/espidf/CMakeFiles/__idf_espidf.dir/__/src/soundISR.c.obj.d
 -o esp-idf/espidf/CMakeFiles/__idf_espidf.dir/__/src/soundISR.c.obj
 -c /home/имяпользователя/каталогпроекта/src/soundISR.c
/home/имяпользователя/каталогпроекта/src/soundISR.c: In function 'timer0_ISR':
/home/имяпользователя/каталогпроекта/src/soundISR.c:21:2: error: #error This is dummy error.
 #error This is dummy error.
  ^~~~~

Теперь нам остается только немного модифицировать эту командную строку, чтобы добавить опцию -S и имя выходного генерируемого файла ассемблера.

4. Чтобы не вбивать каждый раз огромную командную строку для компилятора, целесообразно для компиляции отдельного модуля создать специальный bash-скрипт, примерно такой:

#!/bin/bash
# Файл скрипта toasm.sh, предназначенный для генерации кода ассемблера
# из модуля исходного кода на языке C. Как использовать:
#
# 1. Измените переменные GCC, HC, PRJFOLDER, BUILD, чтобы они соответствовали вашей
#    рабочей среде компиляции.
# 2. Для генерации кода ассемблера (*.S) из кода C (*.c) запустите скрипт командой:
#    $ ./toasm.sh имямодуля.c
#
# Здесь вместо имямодуля.c может быть полный или относительный путь до компилируемого
# модуля на языке C. Файл на языке ассемблера появится в том же каталоге.
 
GCC=/.espressif/tools/riscv32-esp-elf/esp-2021r2-patch3-8.4.0/riscv32-esp-elf/bin/riscv32-esp-elf-gcc
HC=/home/имяпользователя
PRJFOLDER=/каталогпроекта
BUILD=$HC/каталогпроекта/build/esp-idf/espidf/CMakeFiles/__idf_espidf.dir/__/src
 
INC=-I$HC/каталогпроекта/build/config
INC="$INC -I$HC$PRJFOLDER"
INC="$INC -I$HC$PRJFOLDER/include"
INC="$INC -I$HC/esp/esp-idf/components/newlib/platform_include"
INC="$INC -I$HC/esp/esp-idf/components/freertos/include"
INC="$INC -I$HC/esp/esp-idf/components/freertos/include/esp_additions"
INC="$INC -I$HC/esp/esp-idf/components/freertos/include/esp_additions/freertos"
INC="$INC -I$HC/esp/esp-idf/components/freertos/port/riscv/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_hw_support/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_hw_support/include/soc"
INC="$INC -I$HC/esp/esp-idf/components/esp_hw_support/include/soc/esp32c3"
INC="$INC -I$HC/esp/esp-idf/components/esp_hw_support/port/esp32c3/."
INC="$INC -I$HC/esp/esp-idf/components/esp_hw_support/port/esp32c3/private_include"
INC="$INC -I$HC/esp/esp-idf/components/heap/include"
INC="$INC -I$HC/esp/esp-idf/components/log/include"
INC="$INC -I$HC/esp/esp-idf/components/lwip/include/apps"
INC="$INC -I$HC/esp/esp-idf/components/lwip/include/apps/sntp"
INC="$INC -I$HC/esp/esp-idf/components/lwip/lwip/src/include"
INC="$INC -I$HC/esp/esp-idf/components/lwip/port/esp32/include"
INC="$INC -I$HC/esp/esp-idf/components/lwip/port/esp32/include/arch"
INC="$INC -I$HC/esp/esp-idf/components/soc/include"
INC="$INC -I$HC/esp/esp-idf/components/soc/esp32c3/."
INC="$INC -I$HC/esp/esp-idf/components/soc/esp32c3/include"
INC="$INC -I$HC/esp/esp-idf/components/hal/esp32c3/include"
INC="$INC -I$HC/esp/esp-idf/components/hal/include"
INC="$INC -I$HC/esp/esp-idf/components/hal/platform_port/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_rom/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_rom/include/esp32c3"
INC="$INC -I$HC/esp/esp-idf/components/esp_rom/esp32c3"
INC="$INC -I$HC/esp/esp-idf/components/esp_common/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_system/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_system/port/soc"
INC="$INC -I$HC/esp/esp-idf/components/esp_system/port/include/riscv"
INC="$INC -I$HC/esp/esp-idf/components/esp_system/port/public_compat"
INC="$INC -I$HC/esp/esp-idf/components/riscv/include"
INC="$INC -I$HC/esp/esp-idf/components/driver/include"
INC="$INC -I$HC/esp/esp-idf/components/driver/esp32c3/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_pm/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_ringbuf/include"
INC="$INC -I$HC/esp/esp-idf/components/efuse/include"
INC="$INC -I$HC/esp/esp-idf/components/efuse/esp32c3/include"
INC="$INC -I$HC/esp/esp-idf/components/vfs/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_wifi/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_event/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_netif/include"
INC="$INC -I$HC/esp/esp-idf/components/tcpip_adapter/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_phy/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_phy/esp32c3/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_ipc/include"
INC="$INC -I$HC/esp/esp-idf/components/app_trace/include"
INC="$INC -I$HC/esp/esp-idf/components/esp_timer/include"
INC="$INC -I$HC/esp/esp-idf/components/esp-tls"
INC="$INC -I$HC/esp/esp-idf/components/esp-tls/esp-tls-crypto"
INC="$INC -I$HC/esp/esp-idf/components/mbedtls/port/include"
INC="$INC -I$HC/esp/esp-idf/components/mbedtls/mbedtls/include"
INC="$INC -I$HC/esp/esp-idf/components/mbedtls/esp_crt_bundle/include"
INC="$INC -I$HC/esp/esp-idf/components/nvs_flash/include"
INC="$INC -I$HC/esp/esp-idf/components/spi_flash/include"
 
WARN=-Wall
WARN="$WARN -Werror=all"
WARN="$WARN -Wno-error=unused-function"
WARN="$WARN -Wno-error=unused-variable"
WARN="$WARN -Wno-error=deprecated-declarations"
WARN="$WARN -Wextra"
WARN="$WARN -Wno-unused-parameter"
WARN="$WARN -Wno-sign-compare"
WARN="$WARN -Wno-error=format="
WARN="$WARN -Wno-format"
WARN="$WARN -Wno-error=unused-but-set-variable"
WARN="$WARN -Wno-old-style-declaration"
 
OUTPUTASM=$1.S
 
rm $BUILD/*.*$GCC -DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\" $INC -march=rv32imc -ffunction-sections
 -fdata-sections $WARN -nostartfiles -O2 -fmacro-prefix-map=$HC$PRJFOLDER=.
 -fmacro-prefix-map=$HC/esp/esp-idf=IDF -fstrict-volatile-bitfields -fno-jump-tables
 -fno-tree-switch-conversion -std=gnu99 -D_GNU_SOURCE -DIDF_VER=\"v4.4.1-dirty\"
 -DESP_PLATFORM -D_POSIX_READER_WRITER_LOCKS -MD -c $1 -o $OUTPUTASM -S .
 
rm $1.d

5. Запустите скрипт командой:

$ ./toasm.sh путьдомодуля/имямодуля.C

В результате в файле путьдомодуля/имямодуля.S будет сгенерирован код на ассемблере.

6. Теперь можно изменять по своему усмотрению код ассемблера имямодуля.S. Чтобы он использовался в проекте вместо имямодуля.C, подправьте список компилируемых модулей проекта. Например, если для компиляции Вы используете скрипт idf.py, то нужно исправить содержимое файла sources.cmake или CMakeLists.txt проекта. Например, надо в файле CMakeLists.txt заменить soundISR.c на soundISR.c.S:

idf_component_register(REQUIRES "driver"
                                "console"
                                "cmd_system"
                                "cmd_nvs"
                                "esp_wifi"
                                "fatfs"
                       SRCS "cmd_wifi.c"
                            "console_example_main.c"
                            "OneButton.c"
                            #"soundISR.c"
                            "soundISR.c.S"
                            "pwm.c"
                            "wav.c"
                            "sleep.c"
                            "../esp_idf_components/console/commands.c"
                            "cmd_system.c"
                        EMBED_FILES ../wav/32k8bit.wav
                                    ../wav/optan.wav
                    INCLUDE_DIRS ".")

[Ссылки]

1. GCC online documentation site:gcc.gnu.org.

 

Добавить комментарий


Защитный код
Обновить

Top of Page