Студопедия

КАТЕГОРИИ:

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

Пример 4: Копирование Массива Данных на Скалярном Процессоре




Пример демонстрирует два способа копирования массива 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

Пример 5: Копирование Массива Данных на Векторном Процессоре

Пример демонстрирует копирование массива 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"; // признак окончания секции кода.

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

Аналогично скалярной векторная инструкция состоит из левой и правой частей. В левой части содержится команда обращения к памяти на чтение/запись, а в правой операции на векторном процессоре.

Левая часть инструкции

rep 8 data = [ar0++] with data;

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

‘with data or 0’.

Результаты выполнения векторной инструкции попадают в регистр- контейнер afifo.

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

При выполнении арифметических и логических операций, необходимо определить разбиение 64-разрядных векторов, поступающих на вход векторного АЛУ, на элементы. Это действие осуществляется с помощью регистра nb1. В данной программе перед векторными инструкциями следовало бы поместить команды

nb1 = 0;

wtw;// переписывает информацию из теневого регистра nb1

// в рабочий nb2 ,

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

Команда

rep 8 [ar1++] = afifo;

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

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

Пример 6: Операция Взвешенного Суммирования

Демонстрируется пример использования устройства умножения, теневой и рабочей матрицы, входящих в состав векторного процессора 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. Эта перестановка выполняется на устройстве умножения векторного процессора при помощи операции взвешенного суммирования. Основная идея этого преобразования поясняется на рисунке 1:

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

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

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

Регистр nb1 является 64-разрядным регистром. Он отвечает за разбиение теневой матрицы на столбцы.

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

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

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

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

Инструкция

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

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

Результат операции попадает в регистр-контейнер afifo.

Инструкция

rep 1 [ar4] = afifo;

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










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

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