
МП
.pdfзапятой, не включено в рамки настоящего пособия, поскольку оно имеет весьма ограниченное применение в проблематике дисциплины. Подробно ознакомиться с этим вопросом можно в [ 2,4 ] .
Аналогично АЛУ и умножителю, регистры сдвигателя SR1, SR0, SI, SE и SB продублированы в банке дополнительных регистров.
4. Правила написания программ и псевдоинструкции ассемблера
Как показывает практика, восприятие тематики разработки микропроцессорных устройств и систем имеет некоторый «горб сопротивления», связанный, по-видимому, с необходимостью объединения в процессе изложения материала нескольких разнородных дисциплин – механизмов работы процессора, алгоритмов и технологии обработки информации, языка и техники программирования, двоичной арифметики и т.п. Эффективность восприятия дальнейшего материала может быть существенно повышена широким использованием примеров. Наглядность примеров сильно выигрывает их представлением в виде, пригодном для отладки на персональном компьютере; стремлением привести примеры к такому виду объясняется столь на первый взгляд нелогичное размещение
данного раздела в рамках пособия.
В рамках настоящего пособия степень подробности описания языка ассемблера приводится в объеме, минимально необходимом для обеспечения возможности создания работоспособных программ. Транслятор языка Ассемблера процессоров семейства ADSP-21ХХ имеет ряд дополнительных возможностей, направленных на создание существенных удобств для программиста; эти возможности в настоящем пособии не рассматриваются,
читатель может подробно ознакомиться с ними в [ |
3 |
]. |
Программа, создаваемая на языке ассемблера, |
обычно компонуется из |
|
модулей, - функционально законченных |
блоков, допускающих |
|
31 |
|
|
индивидуальную отладку. Файлы, содержащие модули программы или всю программу целиком, написанные на языке Ассемблера ADSP-2181 VisualDsp++, должны иметь расширение .asm.
В рамках настоящего пособия при работе в среде VisualDsp++
программа на языке ассемблера создается как единое целое (без деления на модули), она требует обязательного соответствующего оформления, а также последующих трансляции и линковки.
Программа должна содержать псевдоинструкции ассемблера и команды процессора; каждая из этих конструкций должна заканчиваться символом ";" точки с запятой.
Псевдоинструкции ассемблера используются программой -
ассемблером на этапе трансляции для правильной компоновки модуля; они не создают исполняемых процессором команд и в большинстве случаев направлены на создание удобств при программировании. Псевдоинструкции ассемблера начинаются с символа "." точки. Допустимы некоторые конструкции языка С++.
Ввиду большого объема внутренней (резидентной) памяти и высокой производительности процессора, позволяющих создавать программы весьма высокой сложности, не представляется реальной с психофизической точки зрения возможность успешного отслеживания размещения исходных данных и результатов промежуточных вычислений в памяти процессора. Для облегчения работы с константами и ячейками памяти (переменными) им могут быть приписаны символические имена подобно тому, как это делается в языках высокого уровня. Символическое имя представляет собой набор символов, содержащий заглавные и строчные буквы латинского алфавита,
цифры и символы подчеркивания (Shift -), начинающийся не с цифры и имеющий длину до 32 символов. Набор символов, составляющий символическое имя, может быть произвольным, однако существует
32
некоторый набор зарезервированных слов, не допускающих использования в качестве символических имен. К ним относятся имена регистров, мнемоника операций и псевдоинструкций ассемблера и ряд других слов, использование которых в программе в качестве символических имен будет вызывать сообщение об ошибках трансляции.
Константа и символическое имя задаются в программе псевдоинструкцией
#define имя_константы значение;
#define символическое_имя значение;
Значение константы может быть задано как число в десятичной,
двоичной или шестнадцатеричной системах счисления или в виде арифметического или логического выражения. Запись числа в двоичной системе счисления должна дополняться префиксом B#, а в шестнадцатеричной - префиксом 0х. Числа, записанные без префикса,
интерпретируются ассемблером как десятичные; они могут быть записаны без знака или со знаком минус.
По умолчанию заглавные и строчные буквы символических имен и мнемокодов команд воспринимаются транслятором одинаково, однако при желании можно заставить транслятор воспринимать их как разные символы.
Обращение к константе в программе осуществляется непосредственно по имени. Например
#define koefficient_1 = - 36 + 1024;
#define vhod = 0xA3C;
.
.
ax0 = koefficient_1;
ar = dm(vhod);
33
Переменные могут размещаться как в памяти данных процессора, так и в памяти его программ. При разработке программы в среде VisualDsp++
целесообразно озаботиться проблемой распределения памяти, особенно памяти программ под размещение отдельных модулей. За распределение памяти отвечает файл с расширением .ldf, формируемый линковщиком в соответствие с инструкцией по программированию. При необходимости такой файл можно сформировать вручную объявлением соответствующих секций, следует только помнить, что программа начинает свою работу с нулевого адреса. Пример такого файла представлен на рисунке 10.
ARCHITECTURE(ADSP-2181) SEARCH_DIR( $ADI_DSP\218x\lib ) $OBJECTS = $COMMAND_LINE_OBJECTS ; MEMORY
{
seg_vars |
{ |
TYPE(DM |
RAM) |
START(0x000000) |
END(0x002fff) |
WIDTH(16) } |
|
|
|
|
|
seg_program |
|
{ TYPE(PM RAM) START(0x000000) |
END(0x000fff) |
||
WIDTH(24) } |
|
|
|
|
|
seg_varsp |
{ |
TYPE(PM |
RAM) |
START(0x001000) |
END(0x001fff) |
WIDTH(24)} |
|
|
|
|
|
}
PROCESSOR p0
{
LINK_AGAINST( $COMMAND_LINE_LINK_AGAINST) OUTPUT( $COMMAND_LINE_OUTPUT_FILE )
SECTIONS
{
sec_program
{
INPUT_SECTIONS( $OBJECTS(program) )
}>seg_program sec_vars
Рис.10 начало
34
{
INPUT_SECTIONS( $OBJECTS(vars) )
}>seg_vars sec_varsp
{
INPUT_SECTIONS( $OBJECTS(varsp) ) } >seg_varsp
}
}
Рис. 10 окончание
Представленный файл организует три секции:
- program – в памяти программ TYPE (PM RAM) с нулевого адреса до
0x000fff – естественно, для размещения программы;
-varsp – также в памяти программ со следующего адреса 0x001000 до 0x001fff – для размещения данных (если до конца адресного пространства
–то до 0х3fff);
-vars – в памяти данных TYPE(DM RAM) с нулевого адреса до
0x002fff.
Имя переменной (ячейки памяти) задается в соответствующей секции псевдоинструкцией .var имя_переменной, например:
- в ОЗУ данных:
.section/dm vars;
.var koef2;
.var delta;
…
- в ОЗУ программ:
.section/рm varsр;
.var sinx;
.var destb;
35
Каждой переменной при объявлении может быть присвоено начальное значение, которое она принимает при каждом рестарте процессора:
.var имя_переменной = значение;
В ряде случаев бывает удобным представление переменных в виде массивов из нескольких ячеек памяти; в этом случае при объявлении имени переменной должен быть в квадратных скобках указан размер массива, а
начальные значения его ячеек задаются через запятые, например:
.var massiv_1[5] = -3, B#0000101001011110, 0x287C, 0, 0;
Кольцевые массивы (или кольцевые буферы - см. далее описание ГАД) организуются в резидентной памяти процессора псевдоинструкцией
.var/circ имя_буфера [размер_буфера];
На работу с элементами кольцевых массивов распространяются те же правила, что и для обычных линейных массивов. Отличие заключается в правилах доступа по системе косвенной поставтомодифицирующей адресации, организованной через ГАД1 или ГАД2; принципы такой адресации будут рассмотрены далее при описании ГАД.
В ряде случаев представляется удобной инициализация массива
(занесение начальных значений в его ячейки) из файла данных, хранящегося на носителе компьютера; такая инициализация может быть осуществлена на этапе объявления переменных:
.var имя_массива = <имя_файла>;
при этом начальные значения, подлежащие загрузке в массив, должны быть записаны в файле "в столбик", после последнего значения должен быть помещен код конца строки (нажать клавишу Enter).
Из внешнего файла может быть также включен в программу любой фрагмент, например, список констант или переменных; такое включение
реализуется псевдоинструкцией.
36
#inсlude <имя_файла>;
Псевдоинструкция #inсlude включает текст указанного в угловых
скобках файла в текст основного файла при трансляции модуля.
В целях повышения наглядности и удобочитаемости программы в ее текст полезно включать комментарии. Комментарии не транслируются и не оказывают влияния на характеристики (объем и быстродействие)
загружаемого модуля программы. Комментарии размещаются в тексте программы между командами или между псевдоинструкциями ассемблера и должны либо предваряться двумя знаками дроби - слэшами (//), либо в
символы / и * в виде:
// комментарий
/* комментарий */
В тексте комментариев допускается использование символов
кириллицы. Вложенность комментариев одного типа не допускается. Пример использования комментариев
/* |
|
|
|
Эта |
программа |
реализует функцию.... |
|
*/ |
|
|
|
ar |
= |
dm(koef_beta); /* чтение значения бета */ |
|
ar |
= |
ar + |
1; // увеличение его значения на 1 |
5.Адресация
Процессор поддерживает прямой и косвенный виды адресации. При прямой адресации значение адреса ячейки памяти (или регистра), к которой происходит обращение на запись или чтение, содержится в коде команды,
имеет фиксированное значение и не может меняться в процессе выполнения программы. Этот вид адресации не допускает возможности использования циклических алгоритмических структур для последовательного (или упорядоченного) обращения к разным ячейкам массива.
37
Циклическое обращение и вообще обращение по вычисляемому в программе адресу обеспечивает косвенная адресация, организуемая с использованием генераторов адреса данных ГАД1 и ГАД2.
Обращение к регистрам (за исключением некоторых специальных случаев, которые будут рассмотрены далее) осуществляется по их символическим именам. Регистры разделяются на две большие группы – dreg и reg, отличающиеся возможностями использования в разных командах.
5.1Регистры dreg
Кгруппе dreg относятся регистры вычислительного ядра
AX0, AX1, AY0, AY1, AR,
MX0, MX1, MY0, MY1, MR0, MR1, MR2
SI, SE, SR0, SR1
Исключение составляют регистры AF и MF, не входящие в понятия dreg и reg, поскольку они недоступны ни для записи, ни для чтения информации.
5.2Регистры reg
Кгруппе reg относятся все регистры, включая регистры вычислительного ядра dreg, а также:
- регистры ГАД1 и ГАД2:
I0, I1, I2, I3, I4, I5, I6, I7 – регистры – указатели,
L0, L1, L2, L3, L4, L5, L6, L7 – регистры длины кольцевых буферов,
M0, M1, M2, M3, M4, M5, M6, M7 – модификаторы;
- регистры управления прерываниями
ICNTL, IMASK, IFC
- регистры последовательных портов
TX0, TX1, RX0, RX1
38
-регистр PX в составе CMO
-счетчик циклов CNTR
-регистр статуса ASTAT и др.
5.3 Ячейки памяти данных Ячейки памяти данных в программах обычно рассматриваются как
переменные, правила объявления и инициализации которых с помощью псевдоинструкции ассемблера .var были рассмотрены в разделе 1.4.
Переменные, организуемые как ячейки памяти данных, адресуются как прямо, так и косвенно.
При прямой адресации в ячейки памяти данных может быть записано содержимое любого регистра из группы reg, за исключением регистров AF и MF.
При косвенной адресации в ячейки памяти данных может быть записано содержимое любого регистра только из группы dreg.
Непосредственная запись числа или константы в ячейки памяти данных не допускается ни при прямой, ни при косвенной адресации.
Обращение к переменной в программе осуществляется по имени с указанием типа ОЗУ (dm - данных, pm - программ), в котором эта переменная организована, например, такой фрагмент программы:
.var |
koef_alfa = 0хA348; |
.
.
ar = dm(koef_alfa); ar = ar + 1; dm(koef_alfa) = ar;
39
увеличит на 1 содержимое ячейки с символическим именем koef_alfa,
организованной в памяти данных.
5.4 Ячейки памяти программ Аналогично памяти данных, ячейки памяти программ обычно
рассматриваются как переменные, объявляемые и инициализируемые псевдоинструкциями ассемблера .var.
Ячейки памяти программ допускают только косвенную адресацию только с использованием регистров генератора адреса данных ГАД2, причем обмен информацией (чтение / запись) возможен только с регистрами AY0, AY1, MY0 и MY1.
5.5 Массивы и прямая адресация ячеек в массивах Обращение в режиме прямой адресации допустимо только к
элементам массива, организованного в памяти данных; оно осуществляется по имени с указанием смещения относительно начала массива. Так,
например, в результате выполнения фрагмента программы вида:
.section/dm vars; |
|
|
|
|
||
.var massiv_1[5] = -3, |
B#0000101001011110, 0x287C, 0, 0; |
|||||
|
|
. |
|
|
|
|
|
|
. |
|
|
|
|
ax0 = dm(massiv_1); |
|
|||||
ay0 |
= |
dm(massiv_1 |
+ |
2); |
||
ar |
= |
ax0 + |
ay0; |
|
|
|
dm (massiv_1 |
+ |
1) |
= |
ar; |
врегистр AX0 будет записано число минус 3, в регистр AY0 - число 0х287С,
ав первую по номеру (вторую по счету) ячейку массива будет записана их сумма 0х2879.
40