Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Пример 7: Операция Взвешенного Суммирования (Продолжение)




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

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

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

// исходный вектор

A: long = 3333333322222222hl;

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

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

Matr: long[2] = (0000000100000001hl,

0FFFFFFFF00000001hl);

end ".MyData";

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

<__main>

ar1 = Matr;

nb1 = 80000000h; // разбиение матрицы на два столбца по 32 бита

sb = 03h; // разбиение матрицы на две строки по 32 бита

// весовые коэффициенты загружаются в буфер wfifo, одновременно с этим они транслируются в теневую матрицу, а затем и в рабочую.

rep 2 wfifo = [ar1++], ftw, wtw;

ar2 = A;

ar4 = B;

// операция взвешенного суммирования

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

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

rep 1 [ar4] = afifo;

return;

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

Комментарии к Примеру

Задачей данного примера является одновременное вычисление суммы и разности элементов 64-х разрядного вектора. Это вычисление выполняется на устройстве умножения векторного процессора при помощи операции взвешенного суммирования.

Основная идея этого преобразования поясняется на рисунке 2:

Рисунок 2. Вычисление Суммы и Разности Элементов Вектора

Но прежде требуется разбить матрицу на строки и столбцы.

Команда nb1 = 80000000h; разбивает матрицу на 2 столбца. При этом в обе части регистра попадают одинаковые константы. Таким образом, в nb1 содержится константа 8000000080000000hl.

Команда sb = 03h; разбивает матрицу на 2 строки. При этом в обе части регистра попадают одинаковые константы. Таким образом, в sb (64 разряда) содержится константа 0000000300000003hl.

Команда rep 2 wfifo = [ar1++], ftw, wtw; осуществляет загрузку весовых коэффициентов из памяти в регистр-контейнер wfifo. Как только первое слово весов попадёт в wfifo, сразу же начинается его перекодирование в формат теневой матрицы (эта операция задаётся командой ftw). По завершению перекодирования весов в формат теневой матрицы произойдёт копирование её содержимого в рабочую матрицу. Эта операция занимает один процессорный такт.

Инструкция

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

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

Инструкция

rep 1 [ar4] = afifo;

выгружает результат из afifo во внешнюю память.

Порядок выполнения работы

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

В качестве помощника при написании программы будем использовать программу NMCalculator, которая позволяет сначала визуально задать команду и конфигурацию векторного процессора, а потом получить текст программы на ассемблере из которого можно позаимствовать такие строки как: объявление и инициализация массива весовых коэффициентов; команды конфигурирования векторного процессора задающие разбиение на элементы, константы векторов маскирования и активации; и конечно же саму векторную команду. Т.о., нет необходимости копаться в справочниках по форматам всех команд процессора, а можно просто поставить переключатели на форме в нужное положение и к тому же сразу просмотреть результат этой команды подав значения на входы X и Y.

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

Итак, задание:

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

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

Для компиляции полученного файла необходимо поместить его в каталог, где установлен пакет разработчика для NM6403. Это может быть каталог: С:\ 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. Выполнить обработку полученного блока памяти (массива) в соответствии с вариантом для вашей бригады:

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

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

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

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

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

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

Рекомендации по выполнению: Для выполнения первой части задания воспользуйтесь операцией взвешенного суммирования. Задайте необходимое разбиение рабочей матрицы и весовые коэффициенты. Составьте 64-разрядную константу в которой четные 16-разрядные элементы равны сегодняшнему числу. Затем эту константу можно будет использовать в качестве операнда Y операции взвешенного суммирования, для этого её надо предварительно загрузить, к примеру, в регистр vr. Для выполнения второй части задания следует воспользоваться соответствующей операцией на векторном АЛУ. При этом не забывайте, что разбиение на элементы при использовании векторного АЛУ одинаково для входов Х и Y, и задаётся регистром nb (см. разобранный пример для 11 варианта). Ответьте на вопрос – влияет ли разбиение на результат вашей операции на ВАЛУ?

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

Рекомендации по выполнению: Для выполнения первой части задания воспользуйтесь операцией взвешенного суммирования. Задайте необходимое разбиение рабочей матрицы и весовые коэффициенты. Для выполнения второй части задания следует воспользоваться соответствующей операцией на векторном АЛУ. При этом не забывайте, что разбиение на элементы при использовании векторного АЛУ одинаково для входов Х и Y, и задаётся регистром nb (см. разобранный пример для 11 варианта). Ответьте на вопрос – влияет ли разбиение на результат вашей операции на ВАЛУ?

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

Рекомендации по выполнению: Для выполнения первой части задания воспользуйтесь операцией взвешенного суммирования. Задайте необходимое разбиение рабочей матрицы и весовые коэффициенты. Для выполнения второй части задания следует воспользоваться соответствующей операцией на векторном АЛУ. При этом не забывайте, что разбиение на элементы при использовании векторного АЛУ одинаково для входов Х и Y, и задаётся регистром nb (см. разобранный пример для 11 варианта). Ответьте на вопрос – влияет ли разбиение на результат вашей операции на ВАЛУ?

2.5. Поменять местами соседние четные и нечетные 16-разрядные элементы. Затем, найти результат логического «и» 0-го и 1-го 64-разрядных слов и записать его сразу за концом блока.

Рекомендации по выполнению: Для выполнения первой части задания воспользуйтесь операцией взвешенного суммирования. Задайте необходимое разбиение рабочей матрицы и весовые коэффициенты. Для выполнения второй части задания следует воспользоваться соответствующей операцией на векторном АЛУ. При этом не забывайте, что разбиение на элементы при использовании векторного АЛУ одинаково для входов Х и Y, и задаётся регистром nb (см. разобранный пример для 11 варианта). Ответьте на вопрос – влияет ли разбиение на результат вашей операции на ВАЛУ?

2.6. Найти сумму всех четных 32-разрядных элементов. Затем, обнулить у всех 32-разрядных элементов блока биты, которые в полученной сумме равны нулю.

Рекомендации по выполнению: Для выполнения первой части задания воспользуйтесь скалярным АЛУ. Полученную 32-разрядную сумму выгрузите подряд два раза в память, чтобы получить 64 разрядное слово. Для выполнения второй части задания следует воспользоваться операцией логического «и» на векторном АЛУ с 64-разрядным словом полученным на предыдущем этапе. Чтобы использовать это слово, его необходимо загрузить в ram, причем столько 64-разрядных слов, сколько раз выполняется векторная команда (в нашем случае – 8). При этом не забывайте, что разбиение на элементы при использовании векторного АЛУ одинаково для входов Х и Y, и задаётся регистром nb (см. разобранный пример для 11 варианта). Ответьте на вопрос – влияет ли разбиение на результат вашей операции на ВАЛУ?

2.7. Проинвертировать побитно блок памяти, а затем найти результат логического «и» исходного и проинвертированного блока.

Рекомендации по выполнению: Воспользуйтесь операцией or или and в АЛУ, подключив инверсию входа Х, а на вход Y подав соответствующее значение в зависимости от используемой операции. В данном примере можно обойтись без выгрузки промежуточных результатов в память, воспользовавшись возможностью работы afifo одновременно как на чтение (из головы) так и на запись (в хвост).

2.8. Замените все неотрицательные 4-разрядные элементы нулём, а отрицательные – минус единицей. Затем, замените все -1 на 1, а нулевые элементы оставьте без изменений.

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

2.9. Выполнить арифметическую активацию всех 4-разрядных элементов порогами [-4; 3] (см. предыдущую работу). Затем найти результат «исключающего или» 0-го и 7-го (последнего) 64-разрядных элементов, и записать его сразу за концом блока.

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

2.10. Переставить в каждом 64-разрядном элементе 4-разрядные тетрады в обратном порядке, после чего проинвертировать побитно весь блок памяти.

Рекомендации по выполнению: Для выполнения первой части задания воспользуйтесь операцией взвешенного суммирования. Задайте необходимое разбиение рабочей матрицы и весовые коэффициенты. Для выполнения второй части задания следует воспользоваться соответствующей операцией на векторном АЛУ. При этом не забывайте, что разбиение на элементы при использовании векторного АЛУ одинаково для входов Х и Y, и задаётся регистром nb (см. разобранный пример для 11 варианта). Ответьте на вопрос – влияет ли разбиение на результат вашей операции на ВАЛУ? В данном примере можно обойтись без выгрузки промежуточных результатов в память, воспользовавшись возможностью работы afifo одновременно как на чтение (из головы) так и на запись (в хвост).

2.11. Прибавить всем четным 16-разрядным элементам следующий за ними нечетный элемент, умноженный на 2 и уменьшенный на 1. После чего, найти результат операции исключающего или над 0-ым и 4-ым 16-разрядными элементами блока памяти, результат которой записать в память 64-разрядным словом сразу за концом блока с обнулением оставшихся 48 старших бит слова. Затем, найти сумму всех нечетных 8-разрядных элементов блока памяти в формате 32-разрядного слова.

3. Отладить по шагам полученную программу и убедиться в её правильности. Зафиксировать в отчете текст программы и результаты её работы.

В качестве примера, рассмотрим текст конечной программы с подробными комментариями для 11-го варианта задания:

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

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

Block: word[16] = (0 dup 16); // объявление массива из 16 32-разрядных слов

// c заполнением его нулевыми значениями.

Result: long = 0hl; // 64-разрядное слово для результатов обработки,

// в памяти оно будет расположено сразу за массивом Block.

Entry_Y: long = 00000ffff0000ffffhl; // служебная константа.

Entry_Y1: long = 000000000000ffffhl; // служебная константа.

INC: word = 36072; // служебная константа .

Weights: long[4] = (

00000000000000001hl,

00000000000010002hl,

00000000100000000hl,

00001000200000000hl); // массив весовых коэффициентов.

Weights1: long[8] = (

00000000000000000hl,

00000000000000001hl,

00000000000000000hl,

00000000000000001hl,

00000000000000000hl,

00000000000000001hl,

00000000000000000hl,

00000000000000001hl); // массив весовых коэффициентов.

end ".dataSeg";

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

<__main>

//------заполнение массива Block значениями возрастающими от INC на INC----------

ar0 = Block; // в ar0 загружается адрес массива Block.

gr1 = 16; // в gr1 загружается значение 16,

// равное количеству итераций в цикле.

gr2 = [INC]; // в gr2 загружается значение из памяти по адресу INC,

// равное инкременту значений элементов массива.

gr0 = gr2; // первый элемент = инкременту.

gr1--; // переменная цикла уменьшается на 1 для входа в цикл с

// правильно выставленными условными флагами.

<Loop>

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

if > delayed goto Loop with gr1--;

// две следующих инструкции выполняются до того, как произойдёт переход.

[ar0++] = gr0 with gr0+=gr2 noflags;

nul;

// ------------- здесь произойдёт переход на метку Loop ---------------------

// --------сюда перейдёт программа, когда условие не выполнится--------------

//----------------------преобразование массива Block-----------------------------

// прибавление всем четным 16-разрядным элементам следующего за ним нечетного

// элемента, умноженного на 2 и уменьшенного на 1

//-------------------------------------------------------------------------------

// конфигурирование векторного процессора (ВП).

nb1 = 080008000h; // 4 столбца по 16 бит.

sb = 020002h; // 4 строки по 16 бит.

ar0 = Weights; // в ar0 поместить адрес массива весовых коэффициентов Weights.

rep 4 wfifo = [ar0++], ftw, wtw; // загрузка весовых коэффициентов в ВП.

// подготовка операндов X и Y.

vr = [Entry_Y]; // загрузить в vr 64-разрядное слово из памяти.

ar0 = Block; // в ar0 загружается адрес массива Block.

// собственно, операция взвешенного суммирования.

rep 8 data = [ar0++] with vsum , data, vr;

// выгрузка результатов в память из afifo.

ar0 = Block; // в ar0 загружается адрес массива Block.

rep 8 [ar0++] = afifo; // выгрузка данных

//-------------------------------------------------------------------------------

// операция xor над 0-ым и 4-ым 16-разрядными элементами блока памяти, результат

// которой записывается в память 64-разрядным словом сразу за концом блока с

// обнулением оставшихся старших бит слова

//-------------------------------------------------------------------------------

// конфигурирование векторного процессора (ВП).

nb1 = 080008000h; // 4 столбца по 16 бит.

wtw; // переписать информацию из теневого регистра nb1 в рабочий nb2.

// подготовка операндов X и Y.

ar1 = Block; // в ar1 загружается адрес массива Block.

rep 1 data = [ar1] with data; // загрузка в afifo 0- го 64- разрядного

// элемента массива.

ar1++; // увеличение адреса на 2

ar1++; // для доступа к 1-му 64-разрядному элементу.

// собственно, выполнение операции исключающего или операцией xor

// на векторном АЛУ ( ВАЛУ ).

rep 1 data = [ar1] with data xor afifo;

//обнуление старших 48 разрядов.

ar2 = Entry_Y1; // поместить в ar2 адрес Entry_Y1.

rep 1 data = [ar2] with data and afifo;

// запись результата 64-разрядным словом сразу за концом массива Block,

// т.е. по адресу Result.

ar0 = Result;

rep 1 [ar0] = afifo;

//-------------------------------------------------------------------------------

// нахождение суммы всех нечетных 8-разрядных элементов блока памяти в формате

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

//---------------------------------------------------------------------------

// (1) нахождение частичных сумм для каждого 64-разрядного элемента блока.

// конфигурирование векторного процессора (ВП).

nb1 = 00h; // один столбец.

sb = 02020202h; // 8 строк по 8 бит.

ar0 = Weights1; // в ar0 поместить адрес массива весовых коэффициентов Weights.

rep 8 wfifo = [ar0++], ftw, wtw; // загрузка весовых коэффициентов в ВП.

// подготовка операндов X и Y.

ar0 = Block; // в ar0 загружается адрес массива Block.

// собственно, нахождение суммы нечетных 8-разрядных элементов для каждого

// 64-разрядного слова операцией взвешенного суммирования.

rep 8 data = [ar0++] with vsum , data, 0;

// выгрузка временного результата в память на место массива Block.

ar0 = Block; // в ar0 загружается адрес массива Block.

rep 8 [ar0++] = afifo;

// (2) суммирование 64-разрядных слов частичных сумм на скалярном процессоре.

ar1 = Block; // в ar1 загружается адрес массива Block.

gr2 = 0; // искомая сумма будет накапливаться в gr2.

gr1 = 8; // в gr1 загружается значение 8,

// равное количеству итераций в цикле.

gr0 = [ar1++]; // в gr0 считывается первое четное 32-разрядное слово

// с инкрементом адреса на 1.

ar1++; // повторный инкремент адреса для доступа к четному 32-разрядному слову.

<Loop1>

gr0 = [ar1++] with gr2+=gr0; // накопление суммы с чтением в gr0 из памяти

ar1++; // повторный инкремент адреса для доступа к четному 32-разрядному слову.

gr1--; // декремент счетчика цикла.

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

if > goto Loop1;

// ------------- здесь произойдёт переход на метку Loop1 ---------------------

// --------сюда перейдёт программа, когда условие не выполнится---------------

// в gr2 находится искомая сумма всех нечетных 8-разрядных элементов массива.

return;

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

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

Y= 0 -1 0 -1
3 1 2 0 0
2 0 1 0 0
1 0 0 1 2
0 0 0 0 1
  3 2 1 0

 










Последнее изменение этой страницы: 2018-05-10; просмотров: 238.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...