реклама на сайте
подробности

 
 
> Migration VDSP++->bfin-elf, problems and workarounds
dxp
сообщение Feb 29 2016, 14:55
Сообщение #1


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Всем привет!

* * *

Преамбула.

Некоторое время назад у меня случился переезд с Windows на Linux (смена основной рабочей платформы). И если с софтом для обычной работы/досуга никаких (кроме привыкания) серьёзных проблем нет, то с САПРами всё далеко не так шоколадно. Основная трудность в том, что у некоторых из них нет Linux версий. Отчасти обходным путём может быть использование виртуальной машины, но это не лучший вариант — от Windows тут избавиться не удаётся, а использование становится ещё менее удобным. Поэтому естественно желание применять нативный софт.

Для меня основной проблемой стало то, что на Windows использовался ADI VisualDSP++/Blackfin. На виртуалке это всё поднялось (в том числе и коннект с железкой через ICE-100B), т.ч. как запасной вариант годилось, но хотелось, повторяю, нативного пакета. Особого выбора тут нет — это ADI GNU Toolchain (GCC Blackfin в разных комплектациях). Особенность данного тулчейна в том, что он не предназначен для обычной работы в bare-metal окружении как тот же VDSP++, он предназначен для запуска uClinux на платформе Blackfin.

Исходя из этого, содержание ADI GNU Toolchain'а составляет вариант для сборки приложений под uClinux — называется bfin-uclinux, набор библиотек и опций для всего этого и вариант для сборки С-приложения uboot — называется он bfin-elf. Поскольку uClinux меня не интересует, а нужен инструмент для работы в bare-metal окружении на С++, то выбор пал на bfin-elf.

При освоении данного тулчейна пришлось столкнуться с рядом трудностей, которые были более-менее успешно преодолены, а рабочие проекты портированы с VDSP++ на bfin-elf. Одной из таких трудностей стало то, что не всё необходимое для работы в bare-metal режиме на С++ содержалось в самом тулчейне (bfin-elf), а кое-что оказалось неприемлемого качества. Поэтому в результате этой работы было скомплектовано несколько библиотек (подробнее тут).


* * *

Амбула.

Вся тема возникла из-за того, что штатно (т. е. «из коробки») упомянутый тулчейн не позволяет полноценно работать. Он не включает в себя средства для регистрации обработчиков исключений (прерываний), не поддерживает вызов конструкторов глобальных объектов и имеет некоторые другие недостатки. Собственно, это обусловлено тем, что пакет сырой, «недоделанный» - по сути он предназначался для для того, чтобы собрать uboot, никто на нём разрабатывать bare-metal с использованием C++ приложения не собирался.

Вторым отягчающим обстоятельством является то, что пакет основан на версии gcc 4.3.5, которая является уже довольно старой, и не видно инициатив к развитию (попросту говоря, на данный инструмент «забили»). sad.gif

Ниже перечислены основные проблемы, варианты их решения и обходные пути.

* * *

Отсутствие функции-регистратора обработчиков исключений было восполнено путём подтягивания соответствующей функции из VDSP++ (характерный момент: там в заголовочных файлах всё есть, а вот в библиотеке — нет, поэтому компилируется без вопросов, а на сборке возникает ошибка).

* * *

Вызов конструкторов глобальных объектов в нынешних GCC пакетах осуществляется с помощью функции __libc_init_array из библиотеки тулчейна. Такая функция там есть. Вот только её вызова в basiccrt.S и других стартапах из состава bfin-elf нет.

И второй момент: __libc_init_array вызывает пользовательскую функцию _init(), которая по замыслу предназначена для выполнения низкоуровневой инициализации. Но вот далеко не всегда такая функция нужна, а пользователь вынужден её определять. По-хорошему, такая функция должна была бы лежать в стандартной библиотеке рядом с __libc_init_array, объявленная с атрибутом weak, но этого там не сделано. Поэтому такая weak функция помещена в упомянутую библиотеку.

Кроме того, добавлен файл crt.S, который есть минимально необходимый код стартапа:
  • настройка регистров процессора;
  • перевод в режим супервизора на нижнем приоритете;
  • обработчики исключений по умолчанию;
  • обнуление секции .bss;
  • и, конечно, вызов конструкторов глобальных объектов (__libc_init_array).


Обнуление секции .bss потребовалось потому, что тулчейн генерирует эту секцию незагружаемой (флаг ALLOCATE есть, флага LOAD нету), поэтому при загрузке программы в процессор с помощью gdb данная секция оказывается необнулённой со всеми вытекающими.

* * *

В тулчейн bfin-elf из VDSP++ портировано некоторое количество интринсиков (builtins.h), но, к сожалению, далеко не все, и реализация некоторых не вполне корректна. В частности, мне не хватило доступа к регистру CYCLES (такой интринсик был добавлен), а интринсики cli/sei содержат баг, который приводит к малопонятному сообщению об ошибке (типа, недопустимый символ с индексом nnnn в потоке).

Баг уже известный, суть его сводится к тому, что в реализации, которая сделана с помощью inline assembler, используется паттерн 'r', который соответствует R0-R7 и P0-P5 регистрам процессора, в то время, как инструкции cli/sei допускают только регистры данных, т. е. R0-R7, поэтому правильный паттерн для этих функций не 'r', а 'd'. Оба интринсика так же добавлены в описываемую библиотеку в виде встраиваемых функций __cli/__sei.

* * *

Тулчейн bfin-elf v4.3.5 содержит очень гадкий баг: при некоторых обстоятельствах в обработчике прерываний портится один из регистров (я налетел на порчу регистра I0): регистр используется в теле обработчика, но не сохраняется/восстанавливается в прологе/эпилоге. Это приводит к очень неприятным, непредсказуемым и трудноуловимым глюкам при работе программы. На эту тему составлен багрепорт, но полагаю, что исправляться это не будет.

В качестве обходного пути: обработчики прерываний делать простыми и, главное, избегать в них циклов. Тогда проблем не возникает.

* * *

Из состава VDSP++ подтянут файл с низкоуровневыми функциями настройки pll/clock (pll_set_system_vco/pll_set_system_clocks).

* * *

Утилита для генерации загрузочного образа bfin-elf-ldr имеет следующие недостатки:

  • она тупо грузит все секции, какие есть — например, если в SDRAM находится здоровенная секция, которую не нужно инициализировать, секция всё равно будет загружена, что порождает большой размер файла загрузочного образа и увеличивает время загрузки;
  • загрузочный образ оказывается непригодным для использования в некоторых случаях — конкретно, для загрузки в режиме SPI Slave (описано тут: https://ez.analog.com/thread/71256?start=0&tstart=0), т. к. загрузчик процессора имеет фичу, которая ориентирована на мультизагрузочную конфигурацию образа (загрузчик из состава VDSP++ всегда делает мультизагрузочную конфигурацию, поэтому проблем не создаёт). Фича нигде не описана.


Для обхода этой проблемы написан загрузчик, свободный от этих недостатков: помещает в LDR файл только секции с флагом LOAD и генериует LDR файл в виде мультизагрузочного образа. Загрузчик написан на языке python. Взять его можно тут. Использовать можно как из командной строки, так и из сборочного скрипта. Требует утилит bfin-elf-objdump и bfin-elf-objcopy, обе есть в составе bfin-elf.

* * *

Ну, и последнее. Немало возни было с организацией сборки. Поэтому для облегчения старта создан простой пример, который собирается и работает. Сборка осуществляется с помощью утилиты Scons. Если используется другой инструмент для сборки, то всё равно может оказаться полезным посмотреть опции сборки в сборочном скрипте SConstruct.



P.S. При прохождении этого нелёгкого пути очень большую помощь мне оказал AHTOXA. Как технического плана при погружении в мир GCC, так и морально-психологического, выслушивая нытьё на тему «что ж оно всё такое кривое-горбатое?!..» sm.gif Выражаю ему и Сергею Борщу признательность и благодарность.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 12:59
Рейтинг@Mail.ru


Страница сгенерированна за 0.01362 секунд с 7
ELECTRONIX ©2004-2016