Разработка программного обеспечения реконфигурируемых систем на кристалле семейства A7 фирмы Triscend
Развитие технологии интегральных микросхем направлено на рост быстродействия, пропускной способности и на интеграцию на одном кристалле неоднородных архитектур и устройств. Класс устройств «конфигурируемая система на кристалле» (CSoC) предоставляет возможность значительно увеличить сложность обработки информации, так как конструктивно и логически и процессор и аппаратное ядро объединены на одном кристалле. Ранее реализация такого разнообразия функций была доступна только в рамках одной или нескольких печатных плат с соответствующим увеличением габаритов, ростом энергопотребления и уменьшением быстродействия, то есть со снижением основных функциональных характеристик изделия.
Рассмотрим основные этапы создания программного обеспечения применительно к 32-разрядной системе на кристалле семейства A7 фирмы Triscend. Для работы данного устройства необходимо создание как исполняемого кода для микропроцессорного ядра, так и файла конфигурации матрицы программируемой логики (в отличие от традиционных технологий с применением микроконтроллеров и FPGA/CPLD, где создается либо только программный код, либо только файл конфигурации).
При разработке программной части проекта на основе CSoC A7 взаимодействие с аппаратурой обеспечивается через механизм селекторов и задается адресами программно-доступных ресурсов. После компиляции программы выходной исполняемый код (в формате Intel Hex или Motorola S-record) объединяется с образом конфигурации аппаратной части, при этом создается общий конфигурационный файл, который и загружается в целевое устройство. Система автоматизированного проектирования FastChip совместно со встроенным в кристалл модулем JTAG-интерфейса позволяет произвести загрузку конфигурационного файла как во внутренние ресурсы кристалла (внутреннее статическое ОЗУ и массив программируемой логики), так и в разнообразные внешние запоминающие устройства (Flash-ПЗУ, динамическое и статическое ОЗУ) [1]. Аппаратная поддержка такой загрузки обеспечивается несколькими вариантами JTAG-загрузчика, подключаемого одной стороной к персональному компьютеру, а другой — к проектируемой плате.
CSoC Triscend A7 содержит процессорное ядро ARM7TDMI, которое в настоящее время является промышленным стандартом де-факто для 32-разрядных встраиваемых систем. Особенностью этого процессорного ядра является реализация технологии Thumb. Thumb — это дополнительное расширение к архитектуре ARM. Система команд Thumb является производной от системы стандартных 32-разрядных команд ARM, перекодированных в 16-разрядные коды. Применение системы команд Thumb позволило достичь очень высокой плотности кода, поскольку команды Thumb составляют половину ширины формата команд ARM. В процессе выполнения эти новые 16-разрядные Thumb-коды декомпрессируются процессором в соответствующие эквивалентные команды ARM, которые затем и выполняются процессорным ядром обычным способом. Но технология Thumb — это не только смешанная система команд. Thumb-ориентированные ядра имеют две отдельных системы команд — уникальное достоинство, позволяющее разработчику использовать как производительность 32-разрядной системы команд ARM, так и преимущества малого размера кода системы команд Thumb. Средства декодирующей логики Thumb также чрезвычайно просты, что в свою очередь, сохраняет малые размеры кристалла и не приводит к увеличению энергопотребления. Впервые технология Thumb была встроена в ядро ARM7 еще в 1995 году. Адаптированное под технологию Thumb (Thumb-ориентированное) ядро получило типовое обозначение ARM7TDMI (ARM7, T — наличие Thumb; D — возможность внутрисхемной аппаратной отладки (debug); M — наличие аппаратного перемножителя (multiplier); I — наличие модуля управления отладкой (Embedded ICE)).
Процессорное ядро ARM7TDMI поддерживается следующими компиляторами и системами разработки:
- ARM Development Suite (ADS) фирмы ARM;
- CodeWarrior фирмы Metrowerks;
- Diab Compiler Suite фирмы Wind River;
- MULTI2000 фирмы Green Hills Software;
- MetaDeveloper (компилятор High C/C++ и отладчик SeeCode) фирмы Metaware;
- EWARM фирмы IAR Systems;
- CrossWorks фирмы Rowley Associates (компилятор на основе лицензии GNU).
Указанные системы разработки могут быть использованы для создания программного обеспечения для процессоров с ядром ARM, а также для проведения аппаратной внутрисхемной отладки приложения (пошаговой или с использованием точек останова) через JTAG-интерфейс. Ядро ARM7TDMI имеет встроенный блок поддержки отладки EmbeddedICE [2], однако использование такого механизма при работе кристаллами семейства A7 фирмы Triscend возможно с учетом дополнительного управления, которое производится отдельным программным обеспечением. В частности, при использовании пакета ADS (отладчик AXD) для проведения пошаговой отладки требуется библиотека TriscendA7.dll, подключение которой позволяет настраивать вид сброса и систему отображения устройств памяти при старте приложения (библиотека TriscendA7.dll распространяется свободно и доступна на сайте Triscend по адресу ftp://ftp.triscend.com/software_updates/AXD).
Программная часть может быть выполне на как на языке ассемблера, так и на языках высокого уровня, причем указанные компиляторы обеспечивают выбор типа оптимизации (по скорости исполнения, по занимаемому объему памяти) при построении выходного кода. Особенно гибко настраивать оптимизацию конструкций языка C позволяет система проектирования MULTI2000, в которой предусмотрено множество отдельных параметров компиляции, в том числе распределение различных фрагментов кода приложения между наборами инструкций ARM и Thumb (утилита CodeBalance). Считается, что наиболее оптимального кода для ядра ARM при использовании языков высокого уровня можно достигнуть только с помощью этой среды разработки, хотя данный вопрос является предметом отдельного обсуждения.
Для ATM7TDMI портированы различные операционные системы реального времени (threadX, VxWorks, Integrity, pSOS, WindowsCE, eCOS, uClinux и др.). Тем не менее для первоначального ознакомления наиболее актуальным является изучение монопольного режима работы процессора (то есть без использования ресурсов операционной системы). В этом режиме разработчик должен организовать старт приложения, поддержку стандартного ввода-вывода (например, последовательного интерфейса), организацию рабочего окружения и передачу управления на основную функцию программы, выполненную на языке высокого уровня. Указанные задачи решаются так называемой Сstartup-последовательностью, вид которой, при всей общности процессов, различен для разных систем проектирования.
Адресное пространство системы на кристалле A7 составляет 4 Гбайт. Распределение адресного пространства в рабочем режиме приведено в таблице 1. Распределение адресного пространства в режиме старта приложения иное. После прохождения сигнала сброса процессор начинает выбирать инструкции с нулевого адреса, поэтому в младших адресах должен находиться исполняемый код. С другой стороны, в младших адресах должна располагаться таблица прерываний (вектора входа в обработчики прерываний и исключительных состояний). В простейших приложениях внизу адресного пространства может находиться энергонезависимая память (Flash-ПЗУ), которая, как правило, имеет большое время доступа и «узкую» (8 или 16 бит) шину данных, что уменьшает быстродействие системы, увеличивает время реакции на прерывания. Размещение векторов прерываний в энергонезависимой памяти предполагает неизменность кода обработчиков исключительных ситуаций, что для ряда случаев является существенным ограничением. Гораздо удобнее располагать таблицу прерывания в ОЗУ — при этом можно организовать более быстрый доступ с использованием всей ширины шины данных. Также в этом случае появляется возможность модифицировать таблицу прерываний в процессе работы приложения. Однако расположение ОЗУ по адресу 0x0 после сброса невозможно, так как его содержимое при этом неопределенно.
Для выхода из этой ситуации в процессоре ARM7TDMI предусмотрен режим динамического управления распределением адресного пространства (remap). Каждый из трех типов памяти, где может содержаться исполняемый код (Flash, SRAM, SDRAM), может быть отображен на начало адресного пространства. Такой механизм позволяет на момент загрузки размещать в нижней части адресного пространства энергонезависимую память (Flash-ПЗУ), а после инициализации системы изменять распределение адресного пространства, отображая в младших адресах ОЗУ, которое к этому моменту уже инициализировано cstartup-кодом и содержит таблицу прерываний.
Управление отображением различных устройств памяти на младшие адреса происходит путем записи определенных значений в регистр управления отображением устройств памяти (REMAP_ALIAS_ENABLE_REG), формат которого приведен в таблице 2. В случае, когда одновременно на младшие адреса отображено несколько различных устройств памяти, приоритет выборки будет производиться в следующем порядке:
- внутренняя память загрузки (скрыта от разработчика, существует на момент инициализации системы);
- внешнее Flash-ПЗУ или внешнее статическое ОЗУ (External SRAM);
- внутреннее ОЗУ системы на кристалле (Internal SRAM);
- внешнее синхронное динамическое ОЗУ (SDRAM).
Указанный приоритет выборки не всегда может устраивать разработчика, для смены приоритетов между внешним Flash-ПЗУ и внутренней SRAM используется регистр конфигурации внутренней памяти (SCRATCHPAD_CONFIGURATION_REG).
При изменении распределения адресного пространства необходимо тщательно следить за корректностью исполнения кода и обеспечивать его последовательность и непрерывность, так как сразу после изменения карты памяти следующая инструкция будет выбираться из другой области памяти, код в которой должен быть заранее подготовлен. В процессе разработки приложения возможны различные типы загрузки и разная степень управления отображением устройств памяти со стороны программиста, при этом так же необходимо учитывать следующие соображения:
- в конечных приложениях все программные секции должны быть размещены в энергонезависимой памяти;
- программные секции, содержащие данные, должны быть скопированы во время выполнения сstartup-последовательности в ОЗУ (SRAM или SDRAM);
- программные секции, содержащие исполняемый код, могут быть скопированы в ОЗУ (SRAM или SDRAM) с целью увеличения быстродействия;
- на стадии отладки для ускорения процесса проектирования программные секции могут быть сразу загружены в ОЗУ через JTAG-интерфейс.
Код cstatup-последовательности, кроме управления отображением устройств памяти, до передачи управления функции main() должен выполнить следующие действия:
- инициализировать подсистему памяти;
- инициализировать указатели стека для нескольких режимов работы процессора;
- инициализировать систему прерываний;
- скопировать секции инициализированных данных из области ПЗУ в ОЗУ;
- создать и обнулить области неинициализированных данных в ОЗУ;
- скопировать, если необходимо, исполняемый код на новое место в ОЗУ;
- изменить при необходимости режим работы процессора;
- изменить при необходимости состояния процессора.
При составлении сstartup-последовательности необходимо учитывать особенности конкретной среды разработки, которые рассмотрим на примере программного пакета ADS. Редактор связей (armlink), входящий в указанную среду проектирования, выполняет связывание объектных и библиотечных модулей в единый исполняемый образ, определяет местоположение кода и данных в памяти, создает справочную и отладочную информацию о процессе. Подлежащий связыванию объект состоит из входных секций, содержащих исполняемый код, инициализируемые данные и область памяти, которая должна быть обнулена — атрибуты секций будут RO (Read-Only), RW (Read-Write) или ZI (Zero-Initialized) соответственно. Эти атрибуты используются редактором связей для формирования крупных выходных секций, регионов и образов. Обычно программа состоит из нескольких объектов, которые образуются из исходных файлов, например cstartup. s, main.c, driver.c, поэтому входные секции объединяются в соответствии со своими атрибутами (этот процесс схематично показан на рис. 1). Выходной образ при этом содержит информацию о регионах и выходных секциях, положении этих регионов в памяти на момент загрузки образа и их расположении во время исполнения приложения.
Входные секции могут содержать исполняемый код (RO), инициализируемые данные (RW) — например, установленные в определенное значение глобальные переменные, или описывают область памяти, которая должна быть обнулена (ZI). Инициализированные данные хранятся непосредственно в секции. Секции неинициализированных данных с целью уменьшения размера выходного образа описывают их начальным адресом и размером.
Выходные секции представляют собой непрерывные области, составленные из входных секций с одинаковыми атрибутами. Внутри выходной секции входные секции располагаются последовательно, при этом сортируются по алфавиту в соответствии с именем секции. Последовательный порядок расположения входных секций в выходных секциях может быть изменен при помощи атрибутов, например, для целевого указания расположения кода загрузки в начале выходной секции кода. Регионы содержат непрерывную последовательность от одной до трех выходных секций. Внутри региона сначала располагается выходная секция кода, далее выходная секция инициализируемых данных и в конце — выходная область обнуленных данных. Регион отображается на физическую память проектируемого устройства, например, на область энергонезависимой памяти (ПЗУ) или оперативной памяти (ОЗУ). Однако при этом атрибут RO еще не утверждает, что соответствующая секция размещается именно в ПЗУ, так как ввиду наличия механизма управления отображением устройств памяти в адресном пространстве физически это может быть и ОЗУ, особенно на ранних стадиях отладки.
В автономной встраиваемой системе в момент старта приложения выходной образ должен размещаться в энергонезависимом ПЗУ. Для того чтобы программа исполнялась корректно, необходимо перенести все регионы по заданным адресам и создать обнуленные (ZI) секции данных. Другими словами, в момент старта приложения содержимое оперативной памяти неопределенно, а инициализированные данные (с атрибутом RW) содержатся в ПЗУ, поэтому их необходимо скопировать в ОЗУ, и там же, в соответствии с описанием, заданным в выходной секции, создать область обнуленных данных (ZI).
После инициализации системы в памяти содержится загрузочный образ исполняемого кода. До того, как производить запуск приложения, необходимо перенести входные регионы на их исполняемые адреса. То есть можно говорить о двух различных видах карты памяти:
- На момент загрузки (load view): при этом каждый регион в образе описывается адресом, показывающим его местоположение на момент загрузки, то есть где (по какому адресу) данный регион располагается в ПЗУ.
- Во время исполнения (execution view): при этом регионы описываются реальными адресами, которые существуют при нормальной работе приложения.
- с помощью командной строки (command line options) — этот путь наиболее применим для простой карты памяти, имеющей один или два загрузочных региона и до трех исполняемых регионов;
- с помощью файла описания (scatter-loading description file) — такой способ позволяет создать весьма сложную карту памяти с разнообразным количеством загрузочных и исполняемых регионов.
- 0x0000_0000…0x0000_1FFF и 0xD103_0000…0xD103_1FFF: в этой области может располагаться до 8 кбайт кода программы для процессора;
- 0x0000_2000…0x0000_3FFF и 0xD103_2000…0xD103_3FFF: в этой области могут располагаться до 8 кбайт инициализированных и обнуленных данных.
Физическое окружение Triscend A7 может быть весьма различным и характеризуется разнообразными типами и объемами памяти. В зависимости от сложности разрабатываемого устройства распределение адресного пространства может быть задано в редакторе связей двумя путями:
Рассмотрим вариант управления распределением адресного пространства при помощи командной строки. Пусть необходимо выполнить вариант загрузки Internal, при котором и код и данные содержатся во внутреннем ОЗУ системы на кристалле. Такой вариант удобен при первоначальном тестировании, для быстрой проверки работоспособности устройства. Физически начало внутренней памяти находится по адресу 0xD103_0000, однако после загрузки по JTAG-интерфейсу конфигурационного файла утилита FastChip Device Link произведет настройку системы управления отображением исходя из типа выбранной памяти, в нашем случае это CSOC Internal RAM. Следовательно, у нас должны быть два вида образа памяти — на момент загрузки и на момент выполнения (рис. 2). Мы определяем в редакторе связей параметр ro-base как 0x0 (по этому адресу у нас при загрузке и при исполнении находится код программы), а параметр rw-base как 0xD1032000, то есть устанавливаем его на середину (8 кбайт) доступного пространства внутреннего ОЗУ системы на кристалле. Вследствие работы механизма отображения будут идентичными следующие области памяти по адресам:
Пример содержимого фрагмента командного файла для компиляции и сборки приложения с указанной картой памяти:
В первой строке вызывается ассемблер, в результате получается объектный файл cstartup.o. Во второй строке с помощью компилятора С обрабатывается главный модуль программы и получается файл main.o. В третьей строке вызывается редактор связей, который с помощью атрибутов entry, ro-base, rw-base создает карту памяти, описанную выше.
Последняя строка выполняет обработку выходного файла редактора связей для получения выходного файла в шестнадцатеричном формате start.hex. В дальнейшем этот файл при помощи утилиты FastChip Device Link Utility объединяется с файлом, определяющим конфигурацию аппаратной части проекта, который через JTAG-интерфейс загружается в систему на кристалле.
Адреса и размеры выходных секций являются глобальными, они доступны через соглашения о символах редактора связей в исходном коде программы и отражены в таблице 3. Эта информация необходима для организации переноса выходных секций образа загрузки для создания образа исполнения. В файле cstartup.s, фрагмент которого приведен ниже, с помощью директивы IMPORT сначала получаем доступ к необходимым символам, а затем организуем собственно перенос.
Для ускорения формирования выходной секции инициализированных данных в приведенном примере использованы инструкции групповой загрузки и сохранения регистров процессора.
Приведенный пример управления распределением адресного пространства наиболее прост. В реальных приложениях на основе реконфигурируемых систем на кристалле семейства A7 могут быть применены следующие сценарии загрузки с различным распределением адресного пространства:
- Загрузка кода программы и данных во внутреннее ОЗУ. Используется для быстрых проектов с небольшим объемом кода. Управление распределением адресного пространства производится на уровне FastChip Device Link Utility. Тип загрузки Internal.
- Загрузка кода программы и данных во внешнее синхронное динамическое ОЗУ (SDRAM). Используется на этапе отладки больших проектов. Управление распределением адресного пространства производится на уровне FastChip Device Link Utility. Тип загрузки Ram.
- Загрузка кода программы и данных во внешнее Flash-ПЗУ с последующей перезаписью во время выполнения cstartupпоследовательности исполняемого кода во внешнее синхронное динамическое ОЗУ (SDRAM), а данных — во внутреннее ОЗУ. Используется для проектов высокого быстродействия с большим объемом кода. Управление распределением адресного пространства при загрузке производится на уровне FastChip Device Link Utility, а в процессе работы приложения — программистом в cstartup-файле. Тип загрузки Flash.
- Загрузка кода программы во внешнее Flash-ПЗУ, а данных — во внешнее синхронное динамическое ОЗУ (SDRAM). Используется для проектов среднего быстродействия. Управление распределением адресного пространства при загрузке производится на уровне FastChip Device Link Utility. Тип загрузки Flash_exec.
- Загрузка кода программы во внешнее Flash-ПЗУ, а данных — во внутреннее ОЗУ. Используется для проектов среднего быстродействия при отсутствии внешней SDRAM. Управление распределением адресного пространства при загрузке производится на уровне FastChip Device Link Utility. Тип загрузки Flash_exec_internal.
- Загрузка кода программы и данных во внешнее Flash-ПЗУ с последующей перезаписью во время выполнения cstartup-последовательности исполняемого кода во внутреннее ОЗУ. Используется для проектов высокого быстродействия с небольшим объемом кода. Управление распределением адресного пространства при загрузке производится на уровне FastChip Device Link Utility, а в процессе работы приложения — программистом в cstartupфайле. Тип загрузки Flash_internal.
Динамическое управление распределением адресного пространства на этапе исполнения cstartup-последовательности является особенностью конфигурируемой системы на кристалле Triscend A7. Кроме этого,в cstartup-последовательности необходимо определить указатели стека для различных режимов работы ядра, так как во всех режимах кроме системного и пользовательского используются раздельные области стека. Например, если в режиме прерываний производится вызов функций, то контекст задачи сохраняется по иному указателю стека, нежели в основной программе, поэтому разработчик должен назначать размер стека для предотвращения его возможного переполнения.
Для поддержки функций ввода-вывода языка С, таких, как printf() и scanf(), с целью переназначить поток ввода-вывода на встроенный последовательный интерфейс, в среде проектирования MULTI 2000 необходимо связать функции
с процедурой ввода и вывода одиночного символа через последовательный интерфейс и перекомпилировать соответствующие библиотечные модули. В среде разработки ADS подобная задача решается путем подключения файла retarget.c, в котором также производится конкретизация потока ввода-вывода, причем если в программном окружении имеются иные аппаратные устройства интерфейса, например ЖК-дисплей и клавиатура, то их поддержка конструкциями языка С может быть организована аналогично.
Компиляторы из состава программных пакетов ADS и MULTI2000 кроме стандартного вызова функций с передачей параметров через стек поддерживают соглашение о быстром вызове, при котором первые четыре регистра r0-r3 используются для передачи входных данных и возврата результата, что направлено на уменьшение временных издержек вызова подпрограмм.
В состав программного пакета ADS входит библиотека AS950 с исходным кодом для таких задач цифровой обработки, как дискретно-косинусное преобразование, быстрое преобразование Фурье, фильтрация с конечной и бесконечной импульсной характеристикой, ускоренные математические вычисления.
Таким образом, входящее в состав реконфигурируемой системы на кристалле A7 процессорное ядро полностью поддержано средствами программирования на языках высокого уровня и в сочетании со встроенной аппаратной частью имеет все необходимые характеристики, предъявляемые к быстродействующим устройствам обработки видеоинформации [3]. Опыт реального использования 32-разрядной системы на кристалле для целей формирования и ввода изображений подтверждает высокую пропускную способность и производительность устройств на основе CSoC, что позволяет сделать вывод о перспективности данной технологии для обработки сигналов.
Литература
- В. Березин, Р. Золотухо. 32-разрядная реконфигурируемая система на кристалле A7 фирмы Triscend. // Компоненты и технологии. 2003. № 4.
- Application Note 28. The ARM7TDMI Debug Architecture ARM DAI 0028A.
- Цыцулин А. К. Телевидение и космос: Учеб. пособие. СПб., Изд-во СПбГЭТУ «ЛЭТИ». 2003.