Алгоритм сжатия/распаковки кода для загрузчика Blackfin Печать
Добавил(а) microsin   

Этот документ (перевод апноута EE-257 [1]) описывает алгоритм компрессии/декомпрессии для процессоров ADSP-BF533 и ADSP-BF561 на основе библиотеки ZLib [4]. Код тестировался в VisualDSP++® 3.5, и проект может быть запущен на соответствующих оценочных платах разработчика EZ-KIT Lite® (ADDS-BF533-EZLITE, Rev 1.2 и ADDS-BF561-EZLITE, Rev 1.1).

Обычно файлы загрузчика (loader files, *.ldr), создаваемые средой VisualDSP++, содержат несжатый двоичный код, кроме применения простейшей схемы компрессии типа run-length (RLE, см. "Кодирование длин серий" в Википедии), применяемой для выбрасывания нулей из компилируемого кода. Для больших проектов, которые должны быть сохранены в энергонезависимой памяти, компрессия кода предоставляет значительную экономию на аппаратуре, такой как установленная в системе память FLASH. Код декомпрессии может быть тогда выполнен во время загрузки, путем создания загрузчика второй стадии или кода инициализации, где содержится алгоритм декомпрессии. Подробнее про код инициализации или про то, как происходит процесс загрузки, см. даташит ADSP-BF533 Blackfin Booting Process (EE-240) [2].

[Алгоритм компрессии/декомпрессии загрузки]

Этот алгоритм компрессии требует примерно 50 килобайт дополнительной памяти. Таким образом, он будет полезен только для приложений, которые имеют размер намного больший. Функции компрессии/декомпрессии обрабатываются простым алгоритмом с открытым исходным кодом из библиотеки ZLib [4]. Для удобства использования этого апноута к нему прилагается простой пример сжатого приложения "compressed Blink". Выполните описываемые здесь шаги, и попробуйте запрограммировать приложение CompressedAppIntelHex.ldr с помощью утилиты Flash Programmer [5], чтобы проверить, как все работает. На рис. 3 показан весь процесс целиком.

Шаг 1. Для размещения распакованного образа загрузки программы пользователя (т. е. для содержимого оригинального файла *.ldr) Вы должны выделить в область в памяти SDRAM. Файл настойки линкера .LDF вашего проекта приложения должен быть модифицирован соответствующим образом, чтобы освободить для этого секцию SDRAM подходящего размера. Этот регион памяти должен быть достаточно большим, чтобы разместить весь собранный и распакованный образ приложения целиком, позволяя функции uncompress() сделать распаковку в эту область памяти.

После распаковки образ приложения пользователя будет загружен из SDRAM кодом стандартного загрузчика Boot ROM, находящемся в памяти процессора.

Для процессоров ADSP-BF561 также Вы должны освободить память L2 в диапазоне адресов 0xFEB1FC00 .. 0xFEB1FFE7 путем вывода этой области памяти их всех секций памяти в файле .LDF пользовательского приложения. Эти адреса резервируются для ядра загрузки 2-й стадии (2nd-stage boot kernel). Такая корректировка осуществлена для примера в файле .LDF проекта программы ADSP-BF561 Blink.

Примечание: в рабочем примере кода приложения пользователя, который прилагается к этому апноуту (см. папку Application из архива [7]) это условие выполняется автоматически по той причине, что проект Application это простейшая программа, мигающая светодиодом, вообще не использующая SDRAM/L3. В ней вообще нет отдельного файла LDF (испольуется LDF по умолчанию из подкаталога ldf каталога установки VisualDSP).

Шаг 2. Установите поле UNCOMPR_ADDR в начале файла Init_code.c (находится в папке Init) на адрес назначения памяти, куда будет распаковывать код приложения функция uncompress. Это абсолютный адрес, с которого начинается в адресном пространстве процессора зарезервированная на шаге 1 область памяти SDRAM. В предоставленном примере этот адрес установлен на 0x4000.

Шаг 3. Настройте проект приложения пользователя для сборки образа загрузки (Loader file *.ldr), это делается через страницу Load диалога свойств проекта (Project Options), и используйте для этого формат SPI/ASCII/8-bit. Имейте в виду, что настройка SPI используется как обходное решение для генерации выходных данных в формате ASCII.

Для процессоров ADSP-BF533 укажите следующий путь до файла инициализации проекта: ../Init/Debug/Init.dxe (см. рис. 1).

EE 257 fig1

Рис. 1. Опции загрузчика для процессоров ADSP-BF533.

Для процессоров ADSP-BF561 выберите опции загрузки ядра (Boot kernel options) из списка Category, выберите Use boot kernel, и укажите путь до файла ядра (kernel file): ../Init/Debug/p0.dxe. Также в дополнительных настройках (Additional options) вставьте: ./debug/p0.dxe.

Когда выполняется начальный процесс загрузки, этот объектный файл инициализирует память SDRAM, находит сжатый код приложения пользователя, и распаковывает его в соответствующую зарезервированную на шаге 1 область SDRAM.

Шаг 4. Сначала выполните сборку проекта кода Init, и затем выполните сборку приложения пользователя. Убедитесь, что перед сборкой соответствующий проект выбран активным (выбирается в меню Project -> Set Active Project, имя активного проекта подсвечено жирным шрифтом в дереве файлов Project среды VisualDSP++), и соответствующим образом установлены зависимости проекта (Project -> Update Dependencies). В результате Вы должны получить образ загрузки (файл .LDR) в директории Debug Вашего пользовательского приложения.

Шаг 5. В корневой папке (имеется в виду папка Compression Program BF533 или Compression Program BF561 из архива [7]), отредактируйте файл Compress.bat (используя любой текстовый редактор) чтобы указать путь до целевого образа загрузки собранного пользовательского приложения, а также желаемый уровень компрессии (см. таблицу 1 в приложении с описанием уровней сжатия). Обратите внимание, что вводимый путь должен быть заключен в двойные кавычки ("), и должен использовать прямой слеш (/) или двойной обратный (\\) для отделения друг от друга элементов пути. Некорректно указанный путь до сжимаемого файла или недопустимый уровень сжатия могут привести к непредсказуемым результатам.

Шаг 6. Запустите скрипт Compress.bat, и убедитесь в правильном результате компрессии (он возвращается в строке 6, см. рис. 2) - он должен соответствовать коду возврата из таблицы 2 в Приложении. Окно консоли выполненного скрипта (рис. 2) вернет важные значения, вычисленные в процессе компрессии:

1. Размер исходного файла (источник данных для сжатия).
2. Начальный адрес буфера источника.
3. Количество байт, используемых в буфере источника.
4. Стартовый адрес приложения и количество бай для буфера кода Init.
5. Размер приложения и начальный адрес выходного буфера.
6. Результат компрессии (RESULT = 0 означает успех) и размер образа сжатого приложения.
7. Путь до выходного файла.

EE 257 fig2

Рис. 2. Рабочее окно скрипта компрессии RESULT = 0 (SUCCESS).

Если все прошло успешно, то будет создан файл с именем CompressedApp.ldr сжатого приложения в том же каталоге, что и исходный (не сжатый) файл загрузки (т. е. в каталоге Debug приложения пользователя). Этот файл в ASCII-формате содержит как код Init (код распаковки), так и приложение пользователя (в запакованном виде).

Шаг 7. Сделайте копию файла CompressedApp.ldr в корневой каталог, где Вы должны запустить скрипт IntelHex.bat. Он преобразует файл CompressedApp.ldr из двоичного формата в файл формата Intel HEX [6] с именем CompressedAppIntelHex.ldr. Это преобразование необходимо, чтобы файл загрузки был понят утилитой Flash Programmer.

После этого запустите плагин VisualDSP++ Flash Programmer, и укажите ему прошиваемый файл CompressedAppIntelHex.ldr. Это выполнит копию сжатого образа загрузки в память flash, начиная с адреса 0x20000000. После сброса Boot ROM начнет загрузку с этого адреса памяти flash, загружая код инициализации в память L1 SRAM. Код инициализации настроит SDRAM, и затем распакует образ приложения пользователя по указанному адресу SDRAM (это адрес области, зарезервированной на шаге 1). После этого загрузка продолжится из распакованного образа загрузки (см. рис. 3).

EE 257 fig3

Рис. 3. Процесс компрессии/декомпрессии загружаемого кода.

Пояснения к рис. 3:

1. Выделение области не используемой приложением памяти SDRAM, куда будет записан распакованный образ загрузки (loader image), содержащий приложение пользователя.
2. Установка поля UNCOMPR_ADDR в начале файла кода Init_code.c (находится в папке Init архива [7]) для указания стартового адреса этой зарезервированной области памяти.
3. Сборка проекта кода инициализации (находится в папке Init).
4. Сборка приложения пользователя (папка Application архива [7]). В результате должен появиться файл .LDR в директории Debug проекта приложения пользователя.
5. Редактирование файла скрипта Compress.bat, чтобы указать место нахождения целевого сжимаемого образа загрузки, а также желаемого уровня сжатия.
6. Выполнение скрипта Compress.bat.
7. Выполнение скрипта IntelHex.bat, чтобы преобразовать сжатый файл образа загрузки в формат Intel HEX. В результате получится файл CompressedAppIntelHex.ldr.

После этого запуск VisualDSP++ Flash Programmer и прошивка CompressedAppIntelHex.ldr в энергонезависимую память.

При последующем включении питания (boot time) произойдет следующее:

i – Boot ROM начнет загрузку из начала памяти flash, считывая данные для загрузки по адресу 0x20000000. В результате запустится код проекта Init из памяти L1.
ii – Код Init выполнит инициализацию SDRAM, и распакует код приложения пользователя в специально зарезервированную область памяти SDRAM.
iii – Код Init завершит свою работу, и процесс загрузки продолжится из распакованного образа приложения пользователя.

[Выделение секций памяти в SDRAM]

Листинг 1 показывает секции памяти SDRAM, которые по умолчанию выделяются в adsp-BF533_C.ldf (файл настроек линкера по умолчанию для проектов ADSP-BF533 Blackfin на языке C, который можно найти в папке Blackfin\ldf каталога установки VisualDSP++). Вы можете создавать свои собственные секции памяти, и указывать начало и конец этих секций в адресном пространстве процессора. Так Вы можете частично управлять выделением памяти, которое использует линкер. Для правильного выравнивания данных адреса всех блоков памяти должны быть 32-битные.

MEM_SDRAM0 {
   TYPE(RAM) WIDTH(8)
   START(0x00004000) END(0x07FFFFFF)
}
 
MEM_SDRAM0_HEAP { TYPE(RAM)
   WIDTH(8)
   START(0x00000004) END(0x00003FFF)
}

Листинг 1. Выделение секций, которое существует по умолчанию.

Примечание: назначение файла LDF см. в руководстве "Guide to Blackfin Processor LDF Files (EE-237)", подробное описание содержимого файла LDF и его команд см. в статье [3].

Однако если блоки кода или данных размещаются в определенную пользователем секцию памяти (например с помощью команды .section), то отредактируйте блок LDF, который носит имя SECTIONS. Пример приведен в Листинге 2.

MEM_SDRAM0 {
   TYPE(RAM) WIDTH(8)
   START(0x00004000) END(0x06FFFFFF)
}
 
NEW_SDRAM_SECTION {
   TYPE(RAM) WIDTH(8)
   START(0x07000000) END(0x07FFFFFF)
}
 
MEM_SDRAM0_HEAP {
   TYPE(RAM) WIDTH(8)
   START(0x00000004) END(0x00003FFF)
}
… … … …
 
SECTIONS
{
   my_section
   {
      INPUT_SECTION_ALIGN(4)
      INPUT_SECTIONS(
         $OBJECTS(my_section)
         $LIBRARIES(my_section)
      )
   } >NEW_SDRAM_SECTION
   … … … …

Листинг 2. Определение секций пользователем.

[Приложение]

Вы можете вручную отредактировать определенные файлы и параметры в папке проекта. Ниже описаны эти файлы или параметры, которые могут потребовать модификации (имеются в виду файлы и папки архива [7]).

Папка Application (приложение пользователя). Замените простейший проект, мигающий светодиодами (Blink application) на свое собственное приложение.

Папка Init (приложение инициализации). Если Вы не используете плату ADSP-BF533 EZ-KIT Lite или ADSPBF561 EZ-KIT Lite, то измените секции линкера по умолчанию файла .LDF проекта инициализации (для процессора ADSP-BF533 измените файл Init\adsp-BF533_C.ldf).

Init_code.c. Установите поле UNCOMPR_ADDR в адрес назначения (начало зарезервированного региона SDRAM), куда будет записывать распакованные данные функция uncompress.

Compress.bat. Может быть изменен путь до исходного файла (сжимаемое приложение пользователя) и уровень компрессии.

IntelHex.bat. Если необходимо, то может быть изменено имя выходного файла (2-й параметр).

EE 257 fig4

Рис. 4. Главная директория проекта.

Могут быть применены различные уровни сжатия (таблица 2), и библиотека компрессии Zlib может возвратить разные коды, сигнализирующие об успехе операции сжатия. Эти значения взяты из файла zlib.h (находится в папке zlib архива [7]).

Таблица 1. Уровни компрессии.

Лучшая скорость 1
Компрессия по умолчанию (-1)
Лучшая компрессия 9

В таблице 2 приведены коды возврата функций компрессии/декомпрессии. Отрицательные значения означают ошибки, положительные соответствуют специальным, нормальным событиям.

Таблица 2. Коды возврата функций библиотеки Zlib.

Z_OK 0
Z_STREAM_END 1
Z_NEED_DICT 2
Z_ERRNO (-1)
Z_STREAM_ERROR (-2)
Z_DATA_ERROR (-3)
Z_MEM_ERROR (-4)
Z_BUF_ERROR (-5)
Z_VERSION_ERROR (-6)

Примечание: подробно про уровни сжатия и коды возврата см. [4].

[Ссылки]

1. EE-257 A Boot Compression/Decompression Algorithm for Blackfin® Processors site:analog.com.
2. Как происходит загрузка ADSP-BF533 Blackfin.
3. Linker Description File.
4. zlib 1.2.11 Manual.
5. SAFP: Stand-Alone Flash Programmer.
6. Intel HEX: описание формата файла.
7. 170926EE-257.zip - документация, исходный код.