Пример. Умножение векторов комплексных чисел

Пример. Реализация блочных повторений

n0 .set 456 ; Число блочных повторений 0

n1 .set 12 ; Число блочных повторений 1

n2 .set 5673 ; Число простых повторений 2

n3 .set 7 ; Число простых повторений 3

; ...

MOV #(n0−1), BRC0 ; Счетчик блочного повторения 0

MOV #(n1−1), BRC1 ; Счетчик блочного повторения 1

; ...

RPTBLOCAL loop1−1 ; Блочное повторение глубины 0 n0 раз

; ...

RPT #(n2−1) ; Простое повторение глубины 1 n2 раза

; ...

RPTBLOCAL loop2−1 ; Блочное повторение глубины 1 n1 раз

; ...

RPT #(n3−1) ; Простое повторение глубины 2 n3 раза

; ...

loop2:

; ...

loop1:

 

Пояснение. Каким образом можно реализовать вложенные циклы на языке Assembler?

Определяем несколько констант – число блочных и простых повторений. При блочном повторении есть два комплекта регистров: для счетчика блочного повторения 0 и для счетчика блочного повторения 1. Загружаем в регистры константы, уменьшенные на единицу: если 0 - повторение происходит один раз, если 1 - то два раза и т.д. Задаем первое блочное повторение глубины 0, выполняемое n0 раз до метки loop-1. Внутри блочного повторения с глубиной 0 можно выполнить простое повторение с глубиной 1, повторяемое n2 раз. Заметим, что число повторений можно загрузить в регистр CSR или указать непосредственно в команде, если счетчик повторений известен на этапе ассемблирования. В результате чего выполнение команды будет повторяться определенное количество раз. Например, есть определенная команда, которая повторяется n2 раза, вложенный внутрь одного блока – другой блок, который повторяется n1 раз на глубине 1. А внутри него вкладываем простое повторение два раза. Таким образом, можно организовать цикл по трем переменным, т.е. три вложенных цикла.

Теперь рассмотрим более сложный пример - умножение векторов комплексных чисел, который выполняется только для двухвходовой памяти, т.е. считывание идет по двум адресам.

 

 

N .set 3 ; Длина комплексных векторов

.data ; Секция инициализированных данных

A .int 1, 2, 3, 4, 5,6 ; Вектор комплексных чисел 1

B .int 7, 8, 9, 10, 11, 12 ; Вектор комплексных чисел 2

.bss C, 2*N, ,1 ; Неинициализированная секция

.text ; Секция кода

BCLR ARMS ; Сброс бита ARMS (сигнальный режим)

.arms_off ; Сообщить ассемблеру, что ARMS = 0

AMOV #A, XAR0 ; Указатель на вектор A в XAR0

AMOV #B, XCDP ; Указатель на вектор B в XCDP

AMOV #C, XAR1 ; Указатель на вектор С в XAR1

MOV #(N−1), BRC0 ; Загрузить счетчик циклов в BRC0, т.е. умножение ;поэлементное.

MOV #1, T0 ; В T0 смещение мнимой части - 1

MOV #2, T1 ; В T1 размер комплексного числа - 2

RPTBLOCAL endloop ; Начало цикла

MPY *AR0, *CDP+, AC0 ; Re(Ai)*Re(Bi)=AC0::Im(Ai)*Re(Bi)=AC1

:: MPY *AR0(T0), *CDP+, AC1

MAS *AR0(T0), *CDP+, AC0 ; Im(Ai)*Im(Bi) –AC0::Re(Ai)*Im(Bi)+AC1

:: MAC *(AR0+T1), *CDP+, AC1

endloop: ; Запись Ai*Bi в Сi

MOV pair(LO(AC0)), dbl(*AR1+)

 

Пояснение.

Изначально задаем константу N. Далее в секции данных задаем два вектора с длиной комплексных чисел, заданных в целочисленной формате. Причем первое число – это действительная часть, второе число – мнимая. В результате умножения векторов комплексных чисел, которое производится поэлементно, должен присутствовать вектор комплексных чисел С. Его инициализируем с числом слов 2*N. Сбрасываем бит ARMS и переводим в сигнальный режим, когда процессор выполняет способы адресации данных. Обязательно сообщаем ассемблеру, что ARMS = 0. Затем заносим указатель вектора А в регистр AR0, указатель вектора В - в XCDP, адрес вектора С - в XAR1. Затем в T0 и в T1 задаем структуру мнимого числа, которая позволит хранить эти данные в регистре и тем самым уменьшать время извлечения данных. Задаем цикл, в котором первая команда выполняет два умножения параллельно: действительная часть текущего элемента вектора А умножается на текущую часть элемента вектора В и мнимая часть вектора А умножается на действительную часть вектора В. Результаты заносятся в аккумулятор AC0 и AC1 соответственно. После мы берем регистр AR0, смещенный на T0. Заметим, что в CDP находится адрес мнимой части текущего числа. Применяем команду MAS (Multiple And Substract), которая выполняет умножение с вычитанием. Извлекаем мнимую часть вектора А, умножаем её на мнимую часть вектора В и вычитаем значение аккумулятора AC0. Вторая часть команды, которая работает параллельно, перемножает действительную часть вектора А и мнимую часть вектора В. Затем вычитает значение из аккумулятора. После автоинкриментного выполнения команды MAS, регистр AR0 увеличивается на значение T1. В конце выполнения программы мы записываем результат в элемент вектора С, адрес которого хранится в AR1: младшие части AC0 и AC1 записываем через память двойного доступа в регистр AR1. Это повторяется определенное количество раз.