Научная статья на тему 'Реализация алгоритмов цифровой обработки сигналов ЦОС на ассемблере tms320c6000'

Реализация алгоритмов цифровой обработки сигналов ЦОС на ассемблере tms320c6000 Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
376
76
i Надоели баннеры? Вы всегда можете отключить рекламу.

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Гук Игорь

В настоящей статье рассматриваются правила написания программного кода на ассемблере и способ компоновки проекта с использованием файлов как с С., так с ассемблерным кодом.

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Реализация алгоритмов цифровой обработки сигналов ЦОС на ассемблере tms320c6000»

104 www.finestreet.ru компоненты ЦСП

Игорь ГУК

[email protected]

Реализация алгоритмов ЦОС

на ассемблере TMS320C6000

В настоящей статье рассматриваются правила написания программного кода на ассемблере и способ компоновки проекта с использованием файлов как с С-, так с ассемблерным кодом. Применение ассемблерных вставок направлено в первую очередь на оптимизацию программного кода с учетом архитектуры выбранного ЦСП. Учет архитектуры позволяет повысить эффективность кода. Под повышением эффективности понимается либо увеличение скорости выполнения, либо уменьшение объема занимаемой памяти, либо то и другое одновременно. Однако программный код становится зависимым от выбранного семейства ЦСП. В статье будет показан пример разработки ассемблерного программного кода для проекта цифрового фильтра на ЦСП семейства TMS320C6000, разработанного в предыдущих статьях.

ЦСП — это обычная электронная вычислительная машина (ЭВМ). Архитектура и набор команд такой ЭВМ реализованы с учетом построения на их базе систем ЦОС. Большинство ЦСП имеют блочную структуру (рис. 1):

• ядро ЦСП;

• внутренняя память;

• набор периферийных устройств (периферия);

• шина.

Ядро выполняет обработку данных, а также управляет функционированием ЦСП в целом. Состав ядра:

• устройство управления (УУ), координирующее работу самого ядра и ЦСП в целом;

• арифметико-логическое устройство (АЛУ), выполняющее обработку данных;

• набор регистров общего назначения (РОН) для кратковременного хранения исходных данных и результатов вычислений, используемых в данный момент АЛУ;

• набор регистров специального назначения (РСН) для хранения данных, управляющих процессом функционирования ЦСП.

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

• память программ (ПП) для хранения программного кода,

• память данных (ПД) для хранения исходных данных и результатов вычислений. Обычно вся ПП или ее часть реализуется на

основе постоянного запоминающего устройства (ПЗУ), сохраняющего записанную в него информацию даже при выключенном питании. А ПД строится на основе оперативного запоминающего устройства (ОЗУ), информация в котором исчезает при выключении питания.

Шина осуществляет обмен данными между блоками ЦСП.

Периферия выполняет функции обмена данными с внешними устройствами. Состав периферийных модулей изменяется в очень широких пределах в зависимости от предназначения ЦСП.

Обобщенный алгоритм выполнения программного кода:

• чтение команды из ПП;

• дешифрование команды в УУ;

• чтение операндов из ПД в РОН;

• выполнение операции в АЛУ и формирование результата в РОН;

• перенос результата из РОН в ПД;

• чтение следующей команды и т. д.

Кроме этого, в процессе работы ЦСП

необходимо множество служебных данных: адрес исполняемой команды, адреса операндов, адреса стека, признаки выполнения операции, данные о конфигурации ЦСП и т. д. Все эти данные хранятся в РСН.

Структура ЦСП семейства ТМ8320С6000 фирмы Т1 показана на рис. 2. Отличия от рассмотренной обобщенной схемы следующие:

• ПП и ПД в некоторых модификациях ЦСП могут быть объединены;

• АЛУ содержит два набора модулей по четыре в каждом (.М1, .Б1, .81, .Ь1 и.М2, .Б2, .82, .Ь2);

• РОН включают 32 регистра, разбитых на две части (А0-А15 и В0-В15). Объединение памяти снижает стоимость

процессора. Применение восьми модулей АЛУ позволяет выполнять до восьми опера-

Внешние

устройства

п ДА o'

Е

Р

И Ф Е лл \гУ

Р

И

Я ЛЛ \гУ

ЦСП

Внутренняя память Шина |

Ядро

Рис. 1. Обобщенная структура ЦСП

Внешняя

память

GPIO

McBSP

РМА

Timer

ТСР

УСР

PLL

цеп

Внутренняя память

Шина

Ж.

УУ

р .М1 .М2 Р

О .D1 .D2 О р

н А1 .S1 .S2 Н R1 с

.L1 .L2 н

А15 АЛУ В1Ь

Ядро

Рис. 2. Структура ЦСП TMS320C6000

ЦСП

компоненты 1105

ций за один такт обработки. А наличие 32 РОН значительно снижает временные затраты на операции чтения-записи памяти. Периферия включает модули:

• PPI (Parallel Peripheral Interface) — параллельный периферийный интерфейс, который обеспечивает механизм начальной загрузки процессора;

• GPIO (General Purpose Input/Output) — вход-выход общего назначения, который предназначен для поразрядного ввода-вывода 8-/16-разрядных данных;

• EMIF (External Memory Interface) — интерфейс внешней памяти, который обеспечивает подключение синхронной или асинхронной памяти;

• McBSP (Multi-Channel Buffered Serial Port) — многоканальный буферизированный последовательный порт ввода/вывода реализует последовательные полнодуплексные синхронные каналы ввода/вывода со скоростью обмена до 100 Мбайт/с;

• DMA (Direct Memory Access) — интерфейс прямого доступа к памяти ЦСП, он предназначен для организации каналов пересылки данных между произвольными областями памяти и периферийными модулями без участия ядра ЦСП;

• Timer — таймер-счетчик, реализующий несколько 32-разрядных таймеров-счетчиков, которые могут инициализировать прерывания;

• TCP (Turbo Coprocessor) и VCP (Viterbi Coprocessor) — сопроцессоры, обеспечивающие поддержку голосовых каналов и каналов передачи данных по стандарту 3GPP/IS2000;

• PLL (Phase Lock Loop) — модуль сопряжения с внешним генератором (система ФАПЧ), который обеспечивает умножение частоты внешнего генератора.

В зависимости от модификации ЦСП семейства TMS320C6000 набор периферийных модулей может меняться, могут появиться новые модули или исчезать перечисленные выше.

Для повышения эффективности программного кода часто возникает необходимость переписать его часть на языке низкого уровня — ассемблере.

Строка ассемблерного кода для семейства С6000 имеет следующую структуру:

Здесь:

• первое поле (метка) предназначено для меток, используемых при переходах в программном коде;

• второе поле (параллельность) предназначено для размещения оператора в виде вертикальных линий «II», определяющего режим, когда выполнение текущей команды происходит одновременно (параллельно) с предыдущей;

• третье поле (условие) содержит в квадратных скобках имя регистра, значение которого является условием для выполнения данной строчки ассемблерного кода (при нулевом значении регистра текущая строка считается пустым оператором);

• четвертое поле (мнемоника) является командой, которую необходимо выполнить;

• пятое поле (модуль) указывает, каким именно модулем АЛУ должна выполняться команда;

• шестое и последующие поля (операнд1, операнд2 ...) содержат входные и выходные операнды команды, в качестве которых используются РОН;

• последнее поле (; комментарии) содержит начинающийся с символа «;» текст комментариев, поясняющих смысл выполняемой команды и игнорируемый компилятором. В фигурных скобках указаны необязательные поля. Нулевая позиция в тексте ассемблерного кода отводится под метку. Любой текст, начинающийся с этой позиции, (за исключением комментариев) рассматривается компилятором как метка.

Пример ассемблерного кода:

; Начало цикла: for(i = lenBuff- 1; i >= 0; i--) {

; Определение начального значения переменной цикла SUB .L2 lenBuff_A, 1, i_B ; i = lenBuff- 1;

; Определение начального значения индекса

; входного и выходного буферов

ZERO .L1 count_A ; count = 0;

; Точка обратного перехода при циклических ; вычислениях

loop:

; Чтение данных из входного буфера LDH .D1T1 *+pInpBuff_A[count_A], var_A

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

; var = pInpBuff[count];

; Ожидания завершения операции чтения (4 такта) NOP 4

; Умножение отсчета на два (при помощи сдвига)

SHL .S1 var_A, 1, var_A ; var <<= 1;

; Запись результата в выходной буфер STH .D1T1 var_A, *+pOutBuff_A[count_A]

; pOutBuff[count] = var;

; Инкрементация индекса массива

ADD .L1 count_A, 1, count_A ; count++;

; Условный переход на метку с параллельной ; декрементацией переменной цикла [i_B] B .S2 loop

ll [i_B] SUB .L2 i_B, 1,i_B

; Ожидания завершения операции условного ; перехода (5 тактов)

NOP 5 ; }

; Конец цикла

Жирным шрифтом показаны мнемоники, а курсивом — комментарии. В данном примере реализован цикл умножения входного буфера на два и запись результата в выходной буфер.

Состав основных команд ассемблера процессоров семейства TMS320C6000:

• Арифметические операции:

- сложение (мнемоники — ADD, ADDU, SADD, ADD2, ADDAB, ADDAH, ADDAW);

- вычитание (мнемоники — SSUB, SUB, SUBU, SUBC, SUB2, SUBAB, SUBAH, SUBAW);

- умножение (мнемоники — MPY, MPYU, MPYUS, MPYSU, MPYH, MPYHU, MPYHUS, MPYHSU, MPYHL, MPYHLU, MPYHULS, MPYHSLU, MPYLH, MPYLHU, MPYLUHS, MPYLSHU, SMPY, SMPYHL, SMPYLH, SMPYH);

- сдвиг (мнемоники — SHL, SHR, SHRU, SSHL);

- модуль (мнемоника — ABS).

• Логические действия:

- логические операции (мнемоники — AND, NOT, OR, XOR);

- операции сравнения (мнемоники — CMPEQ, CMPGT, CMPGTU, CMPLT, CMPLTU).

• Работа с памятью:

- чтение (мнемоники — LDB, LDBU, LDH, LDHU, LDW);

- запись (мнемоники — STB, STH, STW).

• Прочие (мнемоники — MV, MVC, MVK,

MVKH, MVKLH, NORM, NEG, ZERO,

LMBD, SAT, B, CLR, EXT, EXTU, SET).

Выше дан только краткий перечень основных команд. Более подробное описание команд можно посмотреть в литературе, поставляемой вместе с CCS под номером SPRU189. Для вызова перечня прилагаемой к ИСР CCS справочной литературы необходимо в главном меню выбрать пункт Help, а в нем подпункт User Manual. (рис. 3). В статье будут описаны только те команды, которые присутствуют в примере ассемблерного кода.

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

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

Затем необходимо определить имя функции, которую нужно переписать на ассемблере. Для примера выбрана функция convolution(). Необходимо установить курсор на файл convolution.cpp, содержащий требуемую функцию, и, щелкнув на нем правой кнопкой мы-

'4/Сбхі 1 DSK (Texas Instruments)/CPU 1 (.6211 Lode Composer Studto

I He E<A Vie* Project Detwj Prorte» <3a Option Took РЄС DSP/BIOS Window Help

¿)<SU * ^ P ■ « • 1 -J Ч „ЯйЗ СП ♦ ••

1 dl ¿||#«а.в|в«л

& Лг апкщрвп :•« •!>, 9! % s: CCStntheW* .

Рис. 3. Вызов перечня дополнительной литературы

{метка:} {параллельность} {[условие]} мнемоника {модуль} операнді, операнд2 ... {; комментарии}

106 компоненты ЦСП

0

и

Рис. 4. Вызов перечня дополнительной литературы

ши, выбрать в контекстном меню пункт File Specific Options (рис. 4a). В появившемся окне на закладке Compiler в разделе Category выбрать пункт Assembly и установить флажок в позиции Keep generated .asm Files (рис. 4б). Нажать кнопку подтверждения ввода параметров (кнопка «OK»). Выбранный файл будет отмечен желтым цветом (рис. 4в), что говорит об отличии параметров его настройки от параметров настройки проекта в целом.

Откомпилировать проект заново, нажав кнопку 0. В папке проекта появится ассемблерный файл convolution.asm. В нем находится сгенерированный CCS ассемблерный код для выбранной функции (рис. 5).

Из этого файла необходимо извлечь две строки:

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

• Соглашение первое. Регистры А0-А9 и В0-В9 могут быть использованы вызываемой функцией без ограничений. Регистры А10-А15 и В10-В15 не могут быть использованы вызываемой функцией без их предварительного сохранения в стеке.

• Соглашение второе. Регистры А1-А2 и В0-В2 быть использованы в качестве регистров

условия при выполнении команд (поле «условие»).

• Соглашение третье. Регистр В3 предназначен для передачи в вызываемую функцию адреса возврата.

• Соглашение четвертое. Регистры А4, В4, А6, В6, А8, В8, А10, В10, А12, В12, А14, В14 предназначены для передачи в вызываемую функцию ее параметров с первого по двенадцатый соответственно. Если параметров больше чем двенадцать, то они передаются через стек. В данном примере передача параметров через стек не рассматривается.

• Соглашение пятое. Регистр В15 предназначен для хранения адреса вершины стека. Шаблон ассемблерного файла выглядит

следующим образом:

; Назначение имен регистров

.asg B3, adrReturn_B

.asg B15, SP

; Определение функции

; Запрет прерываний

MVC .S2 CSR,B0

AND .S2 B0, -2, B1

MVC .S2 B1, CSR

; Сохранение регистров в стеке

STW .D2T2 B0, *-SP[11]

; Алгоритм обработки

; Восстановление регистров

LDW .D2T2 *-SP[11], B0

NOP 4

; Восстановление регистра CSR

MVC .S2 B0, CSR

; Выход из функции

B .S2 adrReturn_B

NOP 5

В разделе «Назначение имен регистров» регистрам общего назначения присваиваются осмысленные имена. Эту функцию выполняет директива предпроцессора «.asg». Обычно этот раздел ассоциируется с той частью программного кода функции на языке Си, где происходит создание локальных переменных, а также с параметрами функции.

Раздел «Определение функции» предназначен для указания секции размещения функции (директива предпроцессора «.sect»), определения имени (директива — «.global») и установки точки входа в функцию (установка метки с именем функции). Для рассматриваемого примера:

.sect «.text» ; секция размещения функции

global _convolution_FPsTls ; имя функции

_convolution_FPsTls: ; точка входа в функцию

Написание ассемблерного кода подразумевает использование программного конвейера. Для корректной работы функции необходимо запретить обработку прерываний на время выполнения конвейера, что обеспечивается установкой нулевого значения в первом бите служебного регистра CSR. Работать напрямую со служебными регистрами в ЦСП семейства TMS320C6000 нельзя. Поэтому в разделе «Запрет прерываний» значение регистра CSR переносится в РОН при помощи специальной команды считывания и записи служебных регистров:

MVC .S2 CSR, B0.

Установка в ноль первого бита производится наложением маски:

Рис. 5. Файл с ассемблерным кодом

<.sect «.text»» — секция, где расположена функция;

(.global _convolution FPsTls» — ассемблерное имя функции.

AND .S2 B0, -2, B1.

ЦСП

компоненты

107

Новое значение перемещается в CSR:

MVC .S2

Старое значение CSR сохранено в РОН В0.

Если необходимо использовать все регистры общего назначения, то в разделе «Сохранение регистров в стеке» значения регистров с номерами 10-15 переносятся в стек. В примере в стеке сохраняется только старое значение CSR. Операция выполняется командой «БТх»:

STW .Б2Ї2 ВО, *^Р[11],

где «Т¥» означает сохранение 32-разрядного значения («В» для 8-ми разрядного и «Н» для 16-ти разрядного); «.В2Т2» означает использование для обработки команды модуля АЛУ «.Г>2»; «*-БР[11]» определяет место в стеке, где сохраняется значение регистра В0 (адрес определяется как разность базового адреса 8Р и смещения, указанного в квадратных скобках).

Перенос данных из памяти в регистр и наоборот осуществляют специальные элементы ядра ЦСП, называемые путем коммутации. Их всего два. Один обеспечивает сохранение/ чтение данных на стороне А (регистры А0-А15), а другой — на стороне В (регистры Б0-Б15). На какой стороне сохранять (или с какой читать) данные, определяют суффиксы «Т1» и «Т2». В данном случае «Т2» указывает на то, что чтение данных производится со стороны В.

Перед выходом из функции необходимо восстановить значения регистров общего назначения с номерами 10-11, а также старое значение CSR. Это действие выполняется в разделе «Восстановление регистров» при помощи команды «ЬВх». В примере происходит восстановление только старого значения регистра С8й

ЬБШ Л2Т2 *-8Р[11], Б0.

Значение полей аналогично полям команды «БТх». Необходимо учитывать, что результат выполнения команды чтения памяти появится в регистре общего назначения только через 4 такта. Поэтому выполняются четыре пустых оператора (ЫСР 4).

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

В разделе «Алгоритм обработки» располагается ассемблерный код алгоритма обработки, который реализует функцию.

Раздел «Выход из функции» определяет точку выхода из функции:

Б .82 adrRetuгn_Б,

где «В» — команда перехода; «.52» — используемый для выполнения команды модуль; «adrReturn_B» — регистр, содержащий адрес возврата из функции.

Команда перехода выполняется с задержкой на пять тактов (ЫСР 5).

При необходимости, перед выполнением команды выхода из функции в регистр A4 заносят возвращаемое значение.

Прежде чем заполнить раздел «Алгоритм обработки», модифицируем программный Си-код функции. Это делается для более полного соответствия кода на языке высокого уровня коду на ассемблере. Такой подход позволяет значительно упростить как написание ассемблерного кода, так и его отладку.

При модификации Си-кода необходимо придерживаться следующих правил:

• не использовать переменную цикла в качестве индекса массива;

• организовывать цикл с использованием де-крементации переменной цикла;

• при возможности заменить индексирование массива инкрементацией или декре-ментацией адреса;

• реализовать алгоритм только при помощи операций, которым можно поставить в соответствие команды ассемблера;

Текст модифицированного С-кода функции convolution() имеет вид:

#include «filter.h»

word16 convolution(word16* pSimpl, word16* pCoeff, word16 sizefilter){ // Объявление локальных переменных word32 sum; // Переменная для накопления суммы word32 mpy; // Переменная для временного хранения // результата умножения word32 n; // Переменная цикла

word16 coeff; // Переменная для коэффициента фильтра word16 simpl; // Переменная для отсчета из линии задержки

// Инициализация локальных переменных sum = 0; // Установка начального значения суммы

// Цикл обработки линии задержки for(n = sizefilter — 1; n >= 0; n--){

// Чтение коэффициента фильтра

// с последующей инкрементацией адреса

coeff = *pCoeff++;

// Чтение отсчета из линии задержки // с последующей инкрементацией адреса simpl = *pSimpl++;

// Умножение коэффициента на отсчет mpy = coeff * simpl;

// Накопление результата умножения sum += mpy;

// Коррекция адреса линии задержки pSimpl--;

// Цикл сдвига линии задержки for (n = sizefilter — 2; n >= 0; n--){

// Чтение предыдущего отсчета simpl = pSimpl[-1];

// Запись предыдущего отсчета на место текущего // с последующей декрементацией адреса *pSimpl-- = simpl;

приведенного выше шаблона ассемблерной функции) имеет вид:

// Нормирование результата суммирования sum >>= l5;

// Выход из функции return sum;

После набора кода необходимо откомпилировать программу, запустить на выполнение и убедиться в ее корректной работе (сравнив выходные файлы, как это описывалось ранее).

Исходя из модифицированного С-кода функции гораздо проще написать ассемблерный код. Один из возможных вариантов ассемблерного кода (написанный на основе

; Назначение имен регистрам

.asg A4, pSimpl_A

asg A5, simpl_A asg A6, sizefilter_A

asg A7, sum_A asg AS, mpy_A asg B0, n_B asg B3, adrReturn_B asg B4, pCoeff_B

asg B6, coeff_B asg B^, SP

word16* pSimpl;

(первый параметр функции) wordl6 simpl; wordl6 sizefilter;

(третий параметр функции) word32 sum; word32 mpy;

Переменная цикла Адрес возврата word16* pCoeff;

(второй параметр функции) wordl6 coeff;

Указатель на стек

; Определение функции .sect «.text»

.global _convolution__FPsTls

_convolution__FPsTls:

секция размещения функции имя функции

точка входа в функцию (метка)

; Запрет прерываний

MVC .S2 CSR, B0

AND .S2 B0, -2, B1

MVC .S2 B1, CSR

; Сохранение регистров в стеке

STW .D2T2 B0, *-SP[11]

; Алгоритм обработки ; Инициализация локальных переменных ZERO .D1 sum_A

= 0;

loop0l:

; Цикл обработки линии задержки ; for(n = sizefilter - 1; n >= 0 n++){

; Определение начального значения переменной цикла SUB .L2 sizefilter_A, 1, n_B ; Точка возврата при циклических вычислениях LDH .D2T2 *pCoeff_B++, coeff_B

; coeff = *pCoeffTmp++; LDH .D1T1 *pSimpl_A++, simpl_A

; simpl = *pSimplTmp++;

NOP 4; Ожидание завершения операции чтения ; данных из памяти

MPY .M1X coeff_B, simp1_A, mpy_A

; mpy = coeff * simpl;

NOP ; Ожидание завершения операции умножения

ADD .S1 sum_A, mpy_A, sum_A

; sum += mpy;

; Условный переход при циклических ; вычислениях и одновременная условная ; декрементация переменной цикла [n_B] B .S2 loop01

ll [n_B] SUB .L2 n_B, 1, n_B

NOP 5 ; Ожидание завершения операции ; условного перехода

; }

; Коррекция адреса линии задержки SUB .L1 pSimpl_A, 2, pSimpl_A

; pSimplTmp-- ;

; Цикл сдвига линии задержки ; for (n = sizefilter — 2; n >= 0; n--){

; Определение начального значения переменной ; цикла

sUb .L2 sizefilter_A, 2, n_B ;

loop02: ; Точка возврата при циклических вычислениях

LDH .D1T1 *pSimpl_A[-1], simpl_A

; simpl = pSimplTmp[-1];

NOP 4 ; Ожидание завершения операции чтения ; данных из памяти

.DlTl simpl_A, *pSimpl_A--

; *pSimp1Tmp--

= simpl;

[n

II [n

L_B]

L_B]

; Условный переход при циклических ; вычислениях и одновременная ; условная декрементация переменной цикла B .S2 loop02

SUB .L2 n_B, 1, n_B

NOP 5 ; Ожидание завершения операции ; условного перехода

; Нормирование результата суммирования SHR .S1 sum_A, 15, sum_A ; sum>>=15;

; Восстановление регистров

LDW .D2T2 *-SP[11], B0 NOP 4

; Восстановление регистра CSR

MVC .S2 B0, CSR

; Выход из функции

; Перемещение возвращаемого значения в регистр A4 MV .S1 sum_A, A4

B .S2 adrReturn_B

NOP 5

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

Bl, CSR

sum

STH

1081 компоненты

ЦСП

н

и

Рис. 6. Исключение файла из процесса компилирования проекта

Необходимо создать файл для исходного кода, набрать текст ассемблерной функции и сохранить его с именем «convolution_my.asm», затем подключить его к проекту, как это было показано в предыдущей статье цикла.

Теперь к проекту подключено два файла, в которых описана одна и та же функция convolution():

• в файле «convolution.cpp» функция представлена кодом на языке

• в файле «convolution_my.asm» эта же функция представлена на ассемблере. Необходимо исключить файл с Си-кодом

из процесса компиляции. Для этого нужно щелкнуть правой кнопкой мыши на файле и выбрать пункт File Specific Options (рис. 6a). В появившемся окне перейти на закладку General и установить флажок в позиции Exclude file from build (рис. 6б).

Затем необходимо произвести компиляцию проекта и запустить программный код на выполнение. Сравнив результаты, полученные при выполнении программы с Си-кодом и с ассемблерным кодом функции convolution(), можно убедиться в их идентичности.

В конце статьи рассмотрим краткое описание применяемых ассемблерных команд.

Суффикс «Х», появившийся у объявления модуля выполнения команды умножения:

говорит о том, что один из входных операндов находится в противоположном относительно модуля наборе РОН. Для этой операции используется специальный элемент ядра ЦСП — кросс-путь. Таких элементов только два — один обеспечивает перенос данных из регистров A0-A15 для модулей с номером 2, а другой — в обратном направлении (данных из регистров B0-B15 для модулей с номером 1). Использовать кросс-путь могут все модули, за исключением модуля «.D».

Ниже приведено краткое описание команд, использованных в рассмотренном примере.

• .asg — директива, которая назначает РОН произвольное имя.

• .sect—директива, которая определяет секцию в памяти, где будет размещен бинарный код функции.

• .global — директива, которая определяет глобальное имя функции.

• MVC — команда перемещения 32-разрядных данных между РОН и РСН. Выполняется модулем «.S2».

• MV — команда перемещения 32-разрядных данных между РОН. Выполняется модулями «.S», «.L» или «.D».

• AND — поразрядная операция «логическое И». Выполняется модулями «.S» или «.L».

• STW — команда заполняет память 32-разрядным знаковым значением из РОН. Выполняется только модулем «.D». Например,

STW .D2T2 Src,*-baseR[offsetR],

где Src — регистр с данными; baseR и offsetR — базовый адрес и смещение для переноса данных соответственно. Значение регистра с базовым адресом после выполнения команды остается прежним.

• STH — команда заполняет память 16-разрядным знаковым значением из РОН. Выполняется только модулем «.D». Например,

STH .D2T2 Src,*baseR--,

где Src — регистр с данными, baseR — базовый адрес для переноса данных. Значение регистра с базовым адресом после выполнения команды декрементируется.

• LDW — команда заполняет регистр 32-разрядным знаковым значением из памяти. Выпол-нятется только модулем «.D». Например,

LDW .D2T2 *-baseR[offsetR], Dst

где Dst — регистр для приема данных, baseR и offsetR — базовый адрес и смещение для чтения данных из памяти соответственно. Значение регистра с базовым адресом после выполнения команды остается прежним. Значение в РОН появится только через 4 такта.

• LDH — команда заполняет регистр 16-разрядным знаковым значением из памяти. Выполняться только модулем «.D». Например,

LDH .D2T2 *baseR++, Dst

где Dst — регистр для приема данных, baseR — базовый адрес для чтения данных из памяти. Значение регистра с базовым адресом после выполнения команды инкрементируется. Значение в РОН появится только через 4 такта.

• SUB — команда определяет разность между значениями двух регистров и заносит результат в третий. Выполняется модулями «.S», «.L» или «.D». Например,

SUB .L2 Src1, Src2, Dst

В данном случае происходит вычитание из значения в регистре Src1 значения в регистре Src2, а результат заносится в Dst. При использовании модуля «.D» вычитание производится из Src2.

• ADD — команда определяет сумму значений двух регистров и заносит результат в третий. Выполняется модулями «.S», «.L» или «.D».

• ZERO — команда заполняет регистр нулями. Выполняется модулями «.S», «.L» или «.D».

• MPY — команда реализует операцию умножения 16-разрядных операндов. Результат 32-разрядный. Выполняется только модулем «.M». Значение в РОН появится через 1 такт.

• B — команда осуществляет переход на метку, имя которой указано в качестве операнда. Переход будет осуществлен через 5 тактов после команды.

• SHR — команда выполняет сдвиг вправо первого операнда на количество разрядов, определяемое вторым операндом. Результат с расширением знака размещается в третьем операнде.

• NOP — пустая операция.

В следующей статье будет показано, как при помощи программного конвейера и параллельного выполнения команд повысить эффективность (скорость выполнения) ассемблерного кода программы. Все файлы проекта можно найти на сайте www.scanti.ru. Напомним, что при первом запуске проекта на новом компьютере необходимо загрузить его через пункт Project главного меню. Затем настроить интерфейс заново и сохранить настройки нового рабочего пространства. ■

MPY .M1X coeff_B, simpl_A, mpy_A,

i Надоели баннеры? Вы всегда можете отключить рекламу.