Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


ОПИСАНИЕ И ПОРЯДОК ПОЛЬЗОВАНИЯ ПРОГРАММОЙ NMCALCULATOR



ЛАБОРАТОРНАЯ РАБОТА №1

 

Архитектура нейромикропроцессоров семейства NeuroMatrix ® NM 640Х и их функциональные возможности

Цель работы: ознакомление с общей архитектурой, функциональными особенностями современных нейромикропроцессоров семейства NeuroMatrix ® NM 640Х (Л1879ВМХ) и его отличиями от других процессоров этого класса с целью изучения основ программирования процессора.

ОПИСАНИЕ И ПОРЯДОК ПОЛЬЗОВАНИЯ ПРОГРАММОЙ NMCALCULATOR

Общие сведения о программе

NMCalculator – интерактивный помощник разработчикам программного обеспечения для процессора Л1879ВМ1. Программа может быть полезна и программистам, осваивающим язык ассемблера и методы программирования векторного узла процессора. Данное приложение является, в некотором смысле, программной моделью векторного узла. В программе нет полного соответствия реальным аппаратным ресурсам процессора Л1879ВМ1, однако, такое абстрагирование упрощает процесс разработки программ, позволяя программисту сосредоточиться на решении основной задачи. NMCalculator предоставляет разработчику возможность сформировать векторную команду и сразу же получить результат. Программа способна эмулировать векторные команды в которых задействуется векторное АЛУ, или рабочая матрица (операции взвешенного суммирования). Пользовательский интерфейс программы состоит из двух частей:

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

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

Формирование векторной команды

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

Рекомендуется соблюдать следующий порядок формирования команды:

  1. Определить операционное устройство: либо рабочая матрица (операция взвешенного суммирования), либо векторное АЛУ. В первом случае – установить флажок " Vsum";
  2. Если необходимо, то подключить регистры маскирования и активации. При работе с векторным АЛУ задать требуемую арифметико-логическую операцию в группе переключателей " Operations";
  3. Задать необходимое разбиение матрицы;
  4. Ввести входные значения.

Действия пользователя по формированию команды отображаются в поле " Command". Обозначения, принятые при выводе команды, не соответствуют реальным устройствам процессора Л1879ВМ1. Например, команда маскирования может выглядеть следующим образом: rep 1 with mask M, shift X, activate Y;

В реальной команде вместо операндов M, X и Y необходимо использовать существующие аппаратные ресурсы (data, ram, afifo и т. д.).

Разбиение рабочей матрицы и запись весовых коэффициентов

Для разбиения матрицы на строки и столбцы можно либо воспользоваться выпадающим списком стандартных разбиений (nbl, nbh, sbl, sbh), либо вводить константы разбиения в окна ввода, либо разбить матрицу в визуализаторе с помощью кнопок-переключателей. Все изменения в матрице отображаются в визуализаторе и в окнах ввода. Для удобства 64-х разрядные регистры разбиения (nb1 и sb) разделены на младшие и старшие части. При необходимости, можно скопировать значение младшей части регистра в старшую часть (кнопка " -> " ). Следует учитывать, что при работе с арифметико-логическими командами (в отличие от команд взвешенного суммирования) разбиение можно задать только в регистрах nbl и nbh, то есть вектора на входах X и Y будут иметь одинаковое разбиение. В операции взвешенного суммирования разбиение на столбцы (nbl, nbh) может отличаться от разбиения на строки (sbl, sbh). Весовые коэффициенты можно задать щелчком мыши в визуализаторе матрицы, устанавливая/сбрасывая необходимые биты. Альтернативный способ – вызов окна диалога из всплывающего меню. В этом случае, можно задать значение всей строке, либо одному весовому коэффициенту. В окне диалога предусмотрен ввод шестнадцатеричных и десятичных значений. Для просмотра всех введённых весов можно воспользоваться генератором кода (кнопка " Code" ). Весовые коэффициенты будут записаны в секцию данных в массиве Weights.

Установка входных значений

Входные значения (Entry X, Entry Y), маску (Mask X, Mask Y), пороги для функции активации можно задать щелчком мыши в визуализаторе матрицы на соответствующих регистрах, устанавливая/сбрасывая необходимые биты, либо вводя значения в соответствующие окна ввода.

Генератор кода

Сформированная пользователем команда, входные значения, константы разбиения и другая введённая пользователем информация используются для генерирования листинга ассемблерного кода. В листинге определены секция данных (значения, определённые пользователем) и секция кода – пример реализации функции с вызовом векторной команды. Генератор кода включается кнопкой " Code".

Замечания. При работе с программой, следует помнить, что разрядность векторов в визуализаторе идет справа налево и снизу вверх. Все данные в окнах редактирования отображаются в 16-ричной системе.

ПОРЯДОК ВЫПОЛНЕНИЯ РАБОТЫ

  1. Запустите программу NMCalculator, разверните её на весь экран, и выберите в главном меню: Setup -> Step of grid -> 5 для 15” монитора или Setup -> Step of grid -> 6 для 17” монитора.
  2. Для начала, рассмотрим несколько простых и очевидных примеров использования операции взвешенного суммирования. Выполните следующие действия:

· Выберите операцию взвешенного суммирования, установив флажок на индикаторе vsum.

· Разбейте рабочую матрицу на 16 строк по 4 бита. Для этого, выберите из выпадающего списка поля sbl нужное значение. При этом, это значение будет автоматически скопировано и в старшую часть этого регистра.

· В результате такого разбиения получилась матрица из 16 ячеек. Теперь, в каждую ячейку запишите весовой коэффициент равный 1. Для этого, щёлкая правой кнопкой мыши на ячейке, выберите пункт всплывающего меню Set element … и в появившемся окне введите 1.

На этом конфигурирование векторного процессора заканчивается и он настроен на выполнение определённой функции. Остаётся подать исходные данные на входы Х и Y рабочей матрицы, и мы получим результат вычислений в регистре afifo. При этом если введено/выведено менее 16-ти цифр, то предполагается, что слева число дополняется недостающими нулями. Итак, посмотрим, что же мы получили в результате. Если всё сделали правильно, то в afifo будет число 10 h (16), т.е. это просто сумма 16-ти 4-разрядных тетрад каждая из которых равна 1 h (0001 b ). Далее, выполните следующее:

· Подайте на вход Y 2 h. Как видите, она прибавляется к результату.

· Измените значение на входе X таким образом, чтобы результат снова стал равным 10 h. Занесите в отчет это значение.

· Верните начальные значения входов Х (=1111111111111111 h ) и Y (=0 h ).

· Изменим конфигурацию рабочей матрицы: установите в ноль значение весового коэффициента самой нижней ячейки. При этом значение результата должно стать на единицу меньше ( fh ). Объясните почему это происходит. Пояснения занесите в отчет.

· Удалите одну единицу со входа Х. Какую по-вашему, единицу Вы удалили – старшую или младшую? Как при этом изменится результат? Запомните это для себя.

· Теперь повторите последние 3 пункта, но весовой коэффициент надо установить в ноль не нижней ячейки, а самой верхней. Обратите внимание, что при удалении одной единицы со входа Х, т.е. замене его старшей тетрады на ноль, результат в afifo уже не уменьшается на 1 как прежде. Объясните почему это происходит. Пояснения занесите в отчет.

· Верните начальные значения входов Х (=1111111111111111 h ), Y (=0 h ) и конфигурацию рабочей матрицы.

· Разбейте рабочую матрицу на 2 столбца по 32 бита каждый. Задайте значения весовых коэффициентов рабочей матрицы в левом столбце следующими: самый нижний -1, второй снизу 2 h, а остальные оставьте равными 0. Для того чтобы ввести -1 не обязательно переводить её в ffffffffh, можно вводить прямо в десятичной системе, установив переключатель в окне ввода весового коэффициента на Decimal. Проанализируем результат: 100000010. Младшие 8 цифр (00000010) – это результат прошлой операции по сложению всех тетрад входа Х плюс младшие 32 разряда входа Y. А вот старшие 8 цифр (00000001) – это результат новой операции, которая равна удвоенному значению второй тетрады за вычетом первой тетрады и плюс старшие 32 разряда входа Y. Таким образом, мы запрограммировали векторный узел процессора на одновременное выполнение двух операций над одними и теми же входными данными. Например, можно разбить матрицу на три столбца следующим образом: 5/27/32 или 1/2/21/40. Допустимо использование не всей матрицы.

· Измените слово на входе Х на следующее: 11 h. Выпишите результат операции в отчет и объясните его.

· Измените слово на входе Х на следующее: 1 h. Выпишите результат операции в отчет и объясните его.

  1. Теперь Вам предстоит самостоятельно запрограммировать рабочую матрицу на вычисление 64-разрядного вектора, который в последующих пунктах будет использоваться Вами. Для этого потребуются числа дней рождения Вашей бригады. Исходя из того, что в месяце максимальное число дней 31 = 1 Fh, для разрядности входных данных достаточно 8 бит. Числа необходимо перевести в 16-ричную систему и, при необходимости, дополнить слева нулём до двух 16-ричных цифр. Затем, эти числа записываются по порядку в поле Х. Например, если после перевода получились числа 1 Ah и Ch, то в поле Х их надо ввести так: 1 A 0 C или так: C 1 A, но не так: 1 AC. Это важно потому, что иначе данные не будут соответствовать разбиению матрицы и результат будет отличен от ожидаемого. Теперь разбейте рабочую матрицу на 64 ячейки (8 бит х 8 бит). В каждом столбце будут выполняться свои операции, которые перечислены ниже в порядке от младших разрядов к старшим. Для их решения, необходимо задать нужные весовые коэффициенты и, при необходимости, соответствующие разряды слова на входе Y. В результате получится искомый вектор, отдельные части которого являются решениями этих задач. Итак, задачи:
  1. Вычислите сумму всех дней рождения.
  2. Из самого большого дня рождения вычтите остальные.
  3. Из суммы всех дней рождения, кроме самого малого вычтите самое малое умноженное на 3 h.
  4. Вычислите сумму произведений всех дней рождений на соответствующие им месяца.
  5. Вычислите сумму всех дней рождения за вычетом их количества.
  6. Вычислите сумму всех дней рождения плюс их количество.
  7. Младший байт входа Х.
  8. Противоположное значение старшего байта входа Х, отличного от 00 h.

Значение входов Х, Y, выхода в afifo и конфигурацию рабочей матрицы (в виде таблицы весовых коэффициентов) занесите в отчет в 16-ричной системе.

  1. Кнопкой Clear all очистите конфигурацию процессора. Результат прошлой операции занесите в поле Х. Сейчас, необходимо, с помощью операции взвешенного суммирования поменять местами тетрады в слове Х. Подумайте, как это сделать. Значение выхода в afifo и конфигурацию рабочей матрицы (в виде таблицы весовых коэффициентов) занесите в отчет.
  2. Кнопкой Clear all очистите конфигурацию процессора. Теперь рассмотрим операции векторного АЛУ. Векторное АЛУ, в отличие от скалярного работает над 64-разрядными данными. Чтобы его использовать, снимите флажок vsum. Помните, что разбиение на элементы при использовании векторного АЛУ одинаково для входов Х и Y , и задаётся регистром nb. Занесите в поле Y результат полученный в пункте 3, поле Х оставьте равным 0, а разбиение задайте произвольно. Выберите операцию вычитания. В результате получим: afifo = X Y. Значение входов Х, Y, выхода в afifo и выполняемую операцию занесите в отчет в 16-ричной системе. Рекомендуется записывать в столбик – цифра под цифрой.
  3. Сложите на векторном АЛУ результат прошлой операции с результатом пункта 3 не меняя разбиение. Занесите данные, результат и операцию в отчет. Результат должен быть равен 0 h.
  4. Проинвертируйте побитно на векторном АЛУ результат пункта 3. Подумайте, какие для этого нужно выбрать операции, значения входов Х, Y и разбиение на элементы. Занесите данные, результат и операцию в отчет в двоичной системе. Убедитесь в правильности результата.
  5. Поочерёдно выполните побитовые операции and, or и xor над результатами предыдущего пункта и пункта 3. Все данные, результаты и операции занесите в отчет в двоичной системе. Убедитесь в правильности результатов.
  6. Кнопкой Clear all очистите конфигурацию процессора. Рассмотрим операцию маскирования. Выполните операцию маскирования с векторным умножением (см. раздел 1.4.3), настроив процессор согласно первому примеру в пункте 1, но на Y подайте не 0, а то же, что на Х (1111111111111111 h ). При этом, вектор масок задайте равным: ffffffffffffffff h и 0 h. Все данные, результаты и операции занесите в отчет. Убедитесь в правильности результатов.
  7. Кнопкой Clear all очистите конфигурацию процессора. Выполните операцию логического маскирования (см. раздел 1.4.3), задав на вход Х – результат пункта 3, на вход Y – 8888888888888888 h и Mask = f0f0f0f0f0f0f0f0 h. Все данные, результаты и операции занесите в отчет. Убедитесь в правильности результатов.
  8. Кнопкой Clear all очистите конфигурацию процессора. Рассмотрим обработку данных функцией активации. Выполните операцию арифметической активации входа Х (см. раздел 1.4.4) складывая Х (=f31f05) с нулём на векторном АЛУ. При этом, задайте разбиение на элементы по 8 бит с верхним порогом насыщения равным 15 и соответственно, нижним равным -16. Все данные, результаты и операции занесите в отчет в двоичной системе. Убедитесь в правильности результатов.
  9. Кнопкой Clear all очистите конфигурацию процессора. Выполните операцию логической активации входа Х (см. раздел 1.4.4), приняв Х равным результату пункта 3. Используйте операцию and с Y = ffffffffffffffff h. При этом, разбиение на элементы задайте равным 16 элементам по 4 бита каждый (см. табл. 1-1). Все данные, результаты и операции занесите в отчет в двоичной системе. Убедитесь в правильности результатов.
  10. Кнопкой Clear all очистите конфигурацию процессора. Рассмотрим операцию циклического сдвига вправо операнда Х (см. раздел 1.4.5). Задайте всей матрице, как одной ячейке, весовой коэффициент равный 1 h, чтобы она просто складывала Х и Y. Выполните операцию взвешенного суммирования операнда Х (=0000000000000001 h ) и Y (=0 h ) два раза: с и без операции shift. Все данные, результаты и операции занесите в отчет. Убедитесь в правильности результатов.

ЛАБОРАТОРНАЯ РАБОТА № 2

Программирование нейромикропроцессора NeuroMatrix ® NM 6403

Ц ель работы: ознакомление с языком ассемблера нейромикропроцессора NeuroMatrix ® NM 6403 (Л18789 ВМ1) и возможностями, которые он предоставляет программисту.

ПОРЯДОК ВЫПОЛНЕНИЯ РАБОТЫ

По материалам разделов 2 и 3 изучить структуру формат ассемблерных инструкций структуру микрокоманд (МК), порядок ввода данных, кодирование и выполнение МК.

По материалам раздела 4 ознакомиться с порядком ввода микропрограмм и исходные данные.

Выполнить упражнения из раздела 5 по указанию преподавателя.

Регистры процессора

Основные регистры

К основным регистрам процессора относятся 8 адресных регистров: ar0 - ar7( sp ) и 8 регистров общего назначения: gr0 - gr0, которые используются в большинстве вычислитель­ных операций процессора. Все они 32-х разрядные, доступны как по чтению, так и по записи.

Адресные регистры

Адресные регистры делятся на две равноправные группы. В первую входят ar0-ar3, а во вторую ar4..ar7. Это связано с наличием двух адресных устройств в процессоре.

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

Примеры использования адресных регистров:

ar0 = ar5; // копирование.

ar2 = ar3 + gr3; // модификация.

[ar4++] = gr7 with gr7 -= gr4; // запись в память.

Адресный регистр ar7 используется процессором в качестве указателя стека адресов возврата sp(Stack Pointer). Это означает, что ar7 модифицируется автоматически, когда происходит вызов функции или прерывания, а также возврат из функции или из прерывания.

Регистры общего назначения

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

[gr0] = gr4; // запись значения регистра gr4 в память

// по адресу, хранящемуся в gr0.

Однако адресные регистры обладают в этом смысле значительно более широкими возможностями.

Примеры использования регистров общего назначения:

gr0 = gr5; // копирование.

gr2 = gr1 + gr3; // модификация.

[ar4++] = gr7 with gr7 -= gr4; // запись в память.

Примечание В процессоре NM6403 не предусмотрены специальные регистры для организации программных циклов.

ПРИМЕРЫ ПРОСТЕЙШИХ ПРОГРАММ

Пример 1: Организация циклов и доступ к памяти

Пример демонстрирует простейший метод организации цикла инструкциями < Loop> - начало цикла и if > goto Loop; - конец цикла при заполнении массива данных возрастающими значениями.

global __main: label; // объявление глобальной метки.

nobits ".MyData1" // секция неинициализированных данных.

global C: word[16]; // объявили массив из 16 32-разрядных слов

end ".MyData1";

begin ". textAAA " // начало секции кода.

< __main>

ar0 = C; // в ar0 загрузили адрес массива С.

gr0 = 0; // в gr0 загрузили значение 0.

gr1 = 16; // в gr1 загрузили значение 16, равное количеству итераций в цикле.

< Loop>

[ar0++] = gr0; // в память по адресу ar0 записываем

// содержимое gr0, а затем увеличиваем

// адрес на 1 (пост-инкрементация).

gr0++; // увеличили значение gr0 на 1

gr1--; // уменьшили значение gr1 на 1, таким образом установили флаг в регистре pswr для дальнейшей проверки

if > goto Loop; // если условие выполнено, осуществляется переход на метку Loop.

return;

end ".textAAA"; // признак окончания секции кода.

Комментарии. В примере массив С в цикле последовательно заполняется возрастающими значениями. Цикл организован путем перехода на заданную метку при выполнении определенных условий (с помощью команд условного перехода).

Пример 2: Копирование массива данных на скалярном процессоре

Пример демонстрирует два способа копирования массива 64-разрядных слов на скалярном процессоре. Первый способ – простое копирование, второй – копирование при помощи регистровых пар.

global __main: label; // объявление глобальной метки.

data ".MyData" // секция инициализированных данных массив А из 16 64-разрядных слов заполняется начальными значениями

global A: long[16] = (0l, 1l, 2l, 3l, 4l, 5hl, 6l, 7l, 8l, 9l,

10l, 0Bhl, 0Chl, 13l, 14l, 15l);

end ".MyData";

nobits ".MyData1" //секция неинициализированных данных.

global B: long[16]; //объявляется массив В из 16 64-разрядных слов

global C: long[16]; // объявляется массив С из 16 64-разрядных слов

end ".MyData1";

begin ".textAAA" // начало секции кода.

< __main> // простое копирование массива данных на скалярном процессоре

ar0 = A;

ar1 = B;

gr1 = 32; // счётчик цикла ( 32 цикла для копирования 16 64-bit слов)

gr1--; // устанавливается флаг для первого вхождения в цикл

< Loop> // если условие выполнено, осуществляется отложенный переход на метку Loop

if > delayed goto Loop with gr1--; // чтение из памяти 32-разрядного слова

gr2 = [ar0++]; // запись в память 32-разрядного слова

[ar1++] = gr2; // копирование массива данных при помощи регистровых пар

ar0 = A;

ar1 = B;

gr1 = 16; // счётчик цикла ( 16 циклов для копирования 16 64-bit слов)

gr1--; // устанавливается флаг для первого вхождения в цикл

< Loop1> // если условие выполнено, осуществляется отложенный переход на метку Loop1

if > delayed goto Loop1 with gr1--;

// чтение из памяти 64-разрядного слова

gr2, ar2 = [ar0++];

// запись в память 64-разрядного слова

[ar1++] = ar2, gr2;

return;

end ".textAAA"; // признак окончания секции кода.

Комментарии. В первой части примера копирование данных осуществляется через один 32-х разрядный регистр. На первом шаге в регистр заносится слово из памяти, на втором оно копируется из регистра в память по другому адресу. В данном случае значения адресных регистров каждый раз увеличиваются на единицу. Поскольку необходимо скопировать массив из шестнадцати 64-х разрядных слов, а за один цикл копирования через регистр переносится одно 32-х разрядное число (младшая или старшая половина 64-х разрядного слова), то для того, чтобы скопировать весь массив необходимо выполнить тридцать два цикла.

Во второй части примера копирование происходит через регистровую пару ar2, gr2 (в регистровой паре каждому адресному регистру поставлен в соответствие регистр общего назначения с тем же номером). За один цикл чтения/записи переносится целиком 64-разрядное слово, поэтому количество циклов копирования равно шестнадцати.

При чтении из памяти в регистровую пару ar2, gr2 = [ar0++]; всега младшая часть 64-разрядного слова попадает в arX, старшая – в grX независимо от того, в каком порядке перечислены регистры в паре. Те же правила действуют при записи содержимого регистровой пары в память. По младшему адресу всегда записывается содержимое регистра arX, по старшему - grX. Таким образом, команда [ar1++] = gr2, ar2; запишет данные в память в том же порядке, в каком они были считаны, независимо от того, в какой последовательности перечислены регистры регистровой пары.

Другим важным моментом, на который стоит обратить внимание, является то, как изменяются значения адресных регистров, используемых для доступа к памяти. И в первой, и во второй части примера используется одна и та же форма записи для инкрементации регистров ar0 и ar1. Однако в первой части, когда выполняется 32-х разрядный доступ к памяти, значения адресных регистров увеличиваются на единицу, а во второй на двойку.

Процессор автоматически распознаёт, какой тип доступа к памяти используется в заданной инструкции – 32-х или 64-х разрядный.

Наличие в инструкции регистровой пары или 64-х разрядного регистра управления приводит к тому, что доступ к памяти ведётся 64-х разрядными словами. Но поскольку единица адресации - 32-х разрядное слово, то при 64-х разрядном доступе простая инкрементация адресного регистра приводит к увеличению его значения на два, например:

gr2 = [ar0++]; // ar0 увеличивается на 1

ar2, gr2 = [ar0++]; // ar0 увеличивается на 2

Пример 3: Копирование массива данных на векторном процессоре

Пример демонстрирует копирование массива 32-разрядных слов с помощью векторного процессора.

global __main: label; // объявление глобальной метки.

data ".MyData" // секция инициализированных данных массив А из 16 32-разрядных слов заполняется начальными значениями

global A: word[16] = (0, 1, 2, 3, 4, 5h, 6, 7, 8, 9, 10, 0Bh, 0Ch, 13, 14, 15);

end ".MyData";

nobits ".MyData1" // секция неинициализированных данных.

global B: word[16]; // объявляется массив В из 16

// 32-разрядных слов

global C: word[16]; // объявляется массив С из 16

// 32-разрядных слов

end ".MyData1";

begin ". textAAA " // начало секции кода.

< __main> // копирование массивов данных

ar0 = A; // с помощью векторного процессора

ar1 = C; // массив А подаётся на векторное АЛУ и попадает в afifo без изменений

rep 8 data = [ar0++] with data; // сохранение во внешней памяти содержимого afifo, заполненного предыдущей векторной инструкцией.

rep 8 [ar1++] = afifo;

return;

end ".textAAA"; // признак окончания секции кода.

Комментарии. Обязательным атрибутом векторной инструкции является количество повторений, определяющее, какое количество 64-х разрядных векторов данных обрабатывается данной инструкцией. В этом смысле векторные инструкции являются SIMD (Single Instruction Multiple Data) инструкциями, выполняя одно и то же действие над несколькими векторами данных.

Команда

rep 8 [ar1++] = afifo;

осуществляет выгрузку данных из afifo в память с постинкрементацией адресного регистра. ( rep кол-во выгружаемых слов). Нельзя выгружать данные по частям (например, сначала 4, а потом еще 4 слова), только целиком все содержимое afifo.

Содержимое afifo не может быть выгружено в регистры процессора или регистровые пары, только в память.

Пример 4: Операция взвешенного суммирования

Демонстрируется пример использования устройства умножения, теневой и рабочей матрицы, входящих в состав векторного процессора NeuroMatrix. В примере рассмотрено использование операции взвешенного суммирования для перестановки байтов внутри 64-х разрядного вектора данных.

global __main: label; // объявление глобальной метки.

data ".MyData" //секция инициализированных данных исходный вектор

A: long = 8877665544332211hl;

// место для хранения результата вычислений

B: long = 0l; // массив Matr содержит значения для заполнения матрицы весовых коэфициентов

Matr: long[8] = (0100000000000000hl,

0001000000000000hl,

0000010000000000hl,

0000000100000000hl,

0000000001000000hl,

0000000000010000hl,

0000000000000100hl,

0000000000000001hl);

end ".MyData";

begin ".textAAA" // начало секции кода.

< __main>

ar1 = Matr;

nb1 = 80808080h; // матрица делится на 8 столбцов по 8 бит

sb = 03030303h; // матрица делится на 8 строк

// весовые коэффициенты загружаются в буфер wfifo

rep 8 wfifo = [ar1++];

ftw; // весовые коэффициенты пересылаются в теневую матрицу с перекодировкой. Эта инструкция всегда выполняется 32 такта.

wtw; // весовые коэф.копируются из теневой матрицы в рабочую

ar2 = A;

ar4 = B; // операция взвешенного суммирования, переставляющая местами байты вектора.

rep 1 data = [ar2] with vsum, data, 0;

// результат операции выгружается из afifo в память

rep 1 [ar4] = afifo;

return;

end ".textAAA"; // признак окончания секции кода.

Комментарии. Задачей данного примера является перестановка порядка элементов в 64-разрядном векторе из состояния A = 8877665544332211hl в состояние В = 1122334455667788hl. Эта перестановка выполняется на устройстве умножения векторного процессора при помощи операции взвешенного суммирования. Основная идея этого преобразования:

Рисунок 3.1 Перестановка Элементов Вектора на Матричном Умножителе

Команда rep 8 wfifo = [ar1++]; осуществляет загрузку весовых коэффициентов из памяти в регистр-контейнер wfifo. Загрузку можно осуществлять и по частям, но так, чтобы не произошло переполнения. Контейнер wfifo имеет глубину в тридцать два 64-х разрядных слова.

Команда ftw; выполняет перекодировку весовых коэффициентов, расположенных в wfifo, в специальный вид, в котором они хранятся в теневой матрице. Эта операция всегда выполняется за 32 такта, однако, она может выполняться параллельно с другими векторными инструкциями.

Команда wtw; копирует весовые коэффициенты из теневой матрицы в рабочую.

Инструкция

rep 1 data = [ar2] with vsum, data, 0;

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

ПОРЯДОК ВЫПОЛНЕНИЯ РАБОТЫ

Практическая часть работы предполагает разработку несложной программы на ассемблере. Программа заполняет блок памяти возрастающими значениями, а затем выполняет некоторые манипуляции над ним. Блок памяти (или массив) будем рассматривать состоящим из элементов определённой разрядности. Для простоты, будем брать только кратные двум разрядности (например, 2, 4, 8, 16, 32, 64 бит) чтобы блок всегда можно было представить из целого количества таких элементов. При этом, элементы имеют порядковые номера от начала блока: 0, 1, 2, … Под четными/нечетными элементами будем понимать элементы с четными / нечетными порядковыми номерами. Ещё раз, следует обратить внимание на то, что нумерация начинается с нуля! , а ноль – это четное число. Так же, следует уточнить, что понимается под положительными/отрицательными числами. Все числа, старший разряд которых =1 процессор воспринимает как отрицательные, а все остальные – как положительные.

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

Для отладки программы воспользуемся специальным отладчиком emudbg. exe, поставляемым вместе с пакетом разработчика для процессора NM 6403.

Задание:

1. Заполнить блок памяти размером в 8 64-разрядных слов (или, что то же самое, – 16 32-разрядных слов) элементами длинной 32 бита возрастающими с INC на INC, где INC = текущий год * (номер бригады + количество человек в бригаде + сумма цифр номера группы). Написать программу для выполнения этого задания (см. разобранный пример для 11 варианта), скомпилировать её в выполняемый файл (*. abs ) и отладить её на отладчике emudbg. exe. Зафиксировать в отчете полученный блок памяти с указанием его начального и конечного адреса.

Для написания текста программы следует воспользоваться любым текстовым редактором не сохраняющим символы форматирования (например, notepad. exe ). Файл следует сохранить с расширением *. asm.

Для компиляции полученного файла необходимо поместить его в каталог, где установлен пакет разработчика для NM 6403. Это может быть каталог: С: \ Program Files \­ Module \ Nmsdk \ bin \ или другой по указанию инженера. Из этого каталога следует запустить программу компилятора следующей командой: nmcc -g step1.asm libc.lib –m, где step1. asm – имя файла с исходными текстами вашей программы. Рекомендуется создать командный (*. bat ) файл с этой командой, чтобы не вводить её каждый раз, а запускать уже этот файл. Если компиляция пройдёт успешно, то в этом же каталоге будут созданы несколько файлов с тем же именем, но с другими расширениями. Нас из них будут интересовать следующие: *. abs – выполняемый файл открываемый из отладчика emudbg. exe, *. map – файл карты памяти в котором можно просмотреть начальные адреса переменных (то, что объявляется в секциях данных) в памяти для наблюдения за их содержимым в процессе отладки. Если же в процессе компиляции будут обнаружены ошибки в тексте программы, компилятор сообщит о них выводом сообщений с указанием номера строки в которой обнаружена ошибка.

Для отладки скомпилированной программы следует запустить программу emudbg. exe всё из того же каталога. Затем, в главном меню выбрать пункт: Цель-> Загрузить программу и в появивадшемся диалоге указать *. abs -файл вашей программы. Чтобы просмотреть различные ресурсы процессора, память и дизассемблированный или исходный код программы следует обратиться к соответствующим подпунктам меню Вид. Рекомендуется, одновременно следить как минимум за содержимым: памяти, используемых программой скалярных и векторных регистров, конфигурацией рабочей матрицы и текущей выполняемой строкой исходного текста. Для доступа к ним необходимо открыть следующие пункты меню Вид: Память, Регистры, Специфика целевой среды и Исходные тексты-> Ваш файл *. asm. При этом, память во многих случаях будет удобнее просматривать не 32-разрядными словами, а 64-разрядными. Для этого: Щелчок правой кнопкой мыши в окне Память-> 64-битные слова. На панели инструментов отладчика расположены кнопки быстрого доступа к наиболее используемым командам, всплывающие подсказки поясняют их назначение. Нам понадобятся: Шаг простой / Шаг обходящий – любой из них для выполнения текущей команды; Снять / поставить точку останова; Запуск / Анимация – любая из них для выполнения уже хорошо отлаженной части программы до точки останова, чтобы не использовать многократно Шаг простой / Шаг обходящий. Чтобы выгрузить программу из отладчика, но оставить конфигурацию процессора и содержимое памяти без изменений следует выбрать: Цель-> Выгрузить программу. Если же необходим полный сброс процессора в исходное состояние, то следует выбрать: Цель-> Перезагрузить цель.

2. Выполнить обработку полученного блока памяти (массива) в соответствии с вариантом для вашей бригады:

Вариант 1. Вычислить контрольную сумму блока памяти (количество единичных бит) и записать её сразу за концом блока.

Рекомендации по выполнению: Воспользуйтесь операцией взвешенного суммирования, разбив рабочую матрицу на 32 строки и 1 столбец. На первом этапе, вычислите сумму четных единичных бит (нумерация, как и для элементов блока памяти начинается с нуля, а ноль – четное число) блока памяти. Полученные восемь 64-разрядных частичных суммы запишите в память для их временного хранения. На втором этапе, вычислите сумму нечетных единичных бит. На третьем этапе, просуммируйте частичные суммы четных и нечетных бит. Выгрузите полученные восемь 64-разрядных частичных суммы в память для их временного хранения. На четвертом этапе, просуммируйте полученные частичные суммы на скалярном процессоре (см. разобранный пример для 11 варианта) и запишите результат в память. Для того чтобы получить доступ к четным/нечетным битам входа Х, необходимо воспользоваться блоком маскирования задав соответствующие векторы масок:

EvenMask: long = 05555555555555555hl; // маска для четных бит (0101).

OddMask: long = 0aaaaaaaaaaaaaaaahl; // маска для нечетных бит (1010).

Вектор масок следует хранить в ram, причем столько 64-разрядных слов, сколько раз выполняется векторная команда (в нашем случае – 8). Кроме того, при суммировании нечетных бит, необходимо подключить регистр сдвига, т.к. разрядность элементов входа Х – 2 бита. Во избежание путаницы, следует четко представлять последовательность выполнения всех этих операций в процессоре (см. предыдущую работу).

Вариант 2 Прибавить всем четным элементам разрядностью 16 бит сегодняшнее число. Затем, вычислить сумму 0-го и 1-го 64-разрядных элементов и записать её сразу за концом блока.

Вариант 3. Умножить каждый элемент блока памяти разрядностью 8 бит на количество человек в бригаде. Затем, найти разность между 2-ым и 0-ым 32-разрядными элементами и записать её сразу за концом блока 64-разрядным словом с обнулением старших 32 разрядов этого слова.

Вариант 4. Вычесть из каждого нечетного элемента разрядностью 32 бита предыдущий (четный) элемент. Затем, найти результат логического «или» 0-го и 4-го элементов разрядностью 16 бит и записать его сразу за концом блока 64-разрядным словом с обнулением старших 48 разрядов этого слова.


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-08-31; Просмотров: 856; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.162 с.)
Главная | Случайная страница | Обратная связь