Примеры применения команд в режиме ARM
В примерах, приведенных ниже, указаны основные способы для достижения высокой эффективности кода с применением основных команд ядра ARM7TDMI. Все эти примеры в основном оптимизированы по размеру кода, а не по скорости выполнения (хотя некоторые из примеров все же позволяют достичь достаточно большой скорости их выполнения).
Использование команд, выполняемых по условиям
Применение условий для логического ИЛИ
CMP Rn,#p ; Если Rn=p OR Rm=q то перейти на Label.
BEQ Label
CMP Rm,#q
BEQ Label
Эквивалентный код:
CMP Rn,#p
CMPNE Rm,#q ; Если условие не выполнено, то провести другой тест.
BEQ Label
|
Абсолютное значение
TEQ Rn,#0 ; Проверить знак
RSBMI Rn,Rn,#0 ; и, если необходимо, дополнить до 2-х.
|
Умножение на 4, 5 или 6
MOV Rc,Ra,LSL#2 ; Умножить на 4,
CMP Rb,#5 ; проверить значение,
ADDCS Rc,Rc,Ra ; закончить умножение на 5,
ADDHI Rc,Rc,Ra ; закончить умножение на 6.
|
Сочетание частичной проверки и проверки диапазона
TEQ Rc,#127 ; Частичная проверка,
CMPNE Rc,#" "-1 ; проверка диапазона
MOVLS Rc,#"." ; ЕСЛИ Rc<=" " ИЛИ Rc=ASCII(127)
; ТО Rc:="."
|
Деление и остаток от деления
Как правило, подпрограммы деления для конкретных задач предоставляется в виде исходной кодов библиотек стандарта ANSI C, поставляемых вместе с набором выбранных средств разработки (ARM Cross Development Toolkit). В целях ознакомления ниже приведены лишь некоторые из подпрограмм деления.
; Делимое находится в Ra, делитель - в Rb.
MOV Rcnt,#1 ; Бит, управляющий делением.
Div1 CMP Rb,#0x80000000 ; Перемещать Rb до тех пор, пока он больше Ra
CMPCC Rb,Ra
MOVCC Rb,Rb,ASL#1
MOVCC Rcnt,Rcnt,ASL#1
BCC Div1
MOV Rc,#0
Div2 CMP Ra,Rb ; Проверить на возможность простого вычитания.
SUBCS Ra,Ra,Rb ; Вычесть если все ОК,
ADDCS Rc,Rc,Rcnt ; разместить соответствующий бит в результат
MOVS Rcnt,Rcnt,LSR#1 ; бит, управляющий сдвигом
MOVNE Rb,Rb,LSR#1 ; делить на 2, пока не закончено.
BNE Div2
; Результат деления размещен в Rc
; Остаток от деления - в Ra.
|
Контроль за переполнением в ARM7TDMI
- Переполнение при умножении чисел без знака с 32-битным результатом
UMULL Rd,Rt,Rm,Rn ; От 3 до 6 (включительно) машинных тактов
TEQ Rt,#0 ; +1 такт при переполнении регистра
BNE overflow
|
- Переполнение при умножении чисел со знаком с 32-битным результатом
SMULL Rd,Rt,Rm,Rn ; От 3 до 6 (включительно) машинных тактов
TEQ Rt,Rd ASR#31 ; +1 такт при переполнении регистра
BNE overflow
|
- Переполнение при умножении с накоплением чисел без знака с 32-битным результатом
UMLAL Rd,Rt,Rm,Rn ; От 3 до 7 (включительно) машинных тактов
TEQ Rt,#0 ; +1 такт при переполнении регистра
BNE overflow
|
- Переполнение при умножении с накоплением чисел со знаком с 32-битным результатом
SMLAL Rd,Rt,Rm,Rn ; От 4 до 7 (включительно) машинных тактов
TEQ Rt,Rd, ASR#31 ; +1 такт при переполнении регистра
BNE overflow
|
- Переполнение при умножении с накоплением чисел без знака с 64-битным результатом
UMULL Rl,Rh,Rm,Rn ; От 3 до 6 (включительно) машинных тактов
ADDS Rl,Rl,Ra1 ; накопление для младшего слова
ADC Rh,Rh,Ra2 ; накопление для старшего слова
BCS overflow ; +1 такт при переполнении обоих регистров
|
- Переполнение при умножении с накоплением чисел со знаком с 64-битным результатом
SMULL Rl,Rh,Rm,Rn ; От 3 до 6 (включительно) машинных тактов
ADDS Rl,Rl,Ra1 ; накопление для младшего слова
ADC Rh,Rh,Ra2 ; накопление для старшего слова
BVS overflow ; +1 такт при переполнении обоих регистров
|
Примечание: контроль за переполнением не имеет смысла при умножении чисел со знаком и без знака с 64-битным результатом, т.к. операнды - 32-битные слова, и поэтому переполнение в этом случае никогда не возникает.
Генератор псевдослучайных чисел
Часто при разработке программ требуются генераторы псевдо-случайных чисел. Самые эффективные алгоритмы основаны на командах исключающее ИЛИ вместе с командами циклического побитового сдвига. К сожалению, для генерации 32-битного результата требуется более одной обратной связи, чтобы добиться максимального диапазона (т.е. 2^32-1 циклов перед повторение псевдослучайной последовательности), поэтому приведенный ниже пример использует в своей работе 33-битный регистр с "рабочими" битами 33 и 20. Формула для работы алгоритма: <новый бит>=<бит 33> EOR <бит 20>, сдвиг влево 33-битного числа и размещение <нового бита> в младшем разряде; эта операция требует обработки всех <новых битов> (т.е. 32 бита). Вся цепочка по получении одного псевдослучайного числа выполняется за 5S машинных тактов:
; Опорное случайное число в Ra (32 бита),
; + 1 бит в младшем бите Rb, используется Rc.
TST Rb,Rb,LSR#1 ; Старший бит поместить во флаг переноса
MOVS Rc,Ra,RRX ; 33-битный циклический сдвиг вправо
ADC Rb,Rb,Rb ; перенос разместить в младшем бите Rb
EOR Rc,Rc,Ra,LSL#12
EOR Ra,Rc,Rc,LSR#20 ; Новое псевдослучайное число размещается Ra.
|
Умножение на константу с использованием операций сдвига
Умножение на 2^n (1,2,4,8,16,32..)
MOV Ra, Rb, LSL #n
Умножение на 2^n+1 (3,5,9,17..)
ADD Ra,Ra,Ra,LSL #n
Умножение на 2^n-1 (3,7,15..)
RSB Ra,Ra,Ra,LSL #n
Умножение на 6
ADD Ra,Ra,Ra,LSL #1 ; multiply by 3
MOV Ra,Ra,LSL#1 ; and then by 2
Умножение на 10 с добавлением числа
ADD Ra,Ra,Ra,LSL#2 ; multiply by 5
ADD Ra,Rc,Ra,LSL#1 ; multiply by 2 and add in next digit
Общий рекурсивный метод для Rb := Ra*C, C - константа:
- Если C - четное, то C = 2^n*D, D - нечетное:
D=1: MOV Rb,Ra,LSL #n
D<>1: {Rb := Ra*D}
MOV Rb,Rb,LSL #n
|
- Если C MOD 4 = 1, то C = 2^n*D+1, D - нечетное, n>1:
D=1: ADD Rb,Ra,Ra,LSL #n
D<>1: {Rb := Ra*D}
ADD Rb,Ra,Rb,LSL #n
|
- Если C MOD 4 = 3, то C = 2^n*D-1, D - нечетное, n>1:
D=1: RSB Rb,Ra,Ra,LSL #n
D<>1: {Rb := Ra*D}
RSB Rb,Ra,Rb,LSL #n
|
Эта часть кода не совсем оптимальна, но близка к этому. Пример ее неоптимальности - умножение на 45:
RSB Rb,Ra,Ra,LSL#2 ; multiply by 3
RSB Rb,Ra,Rb,LSL#2 ; multiply by 4*3-1 = 11
ADD Rb,Ra,Rb,LSL#2 ; multiply by 4*11+1 = 45
|
Другой вариант:
ADD Rb,Ra,Ra,LSL#3 ; multiply by 9
ADD Rb,Rb,Rb,LSL#2 ; multiply by 5*9 = 45
|
Чтение слова при неизвестном выравнивании
; Адрес находится в Ra (32 бита),
; используются регистры Rb, Rc; результат в Rd.
; d должно быть менее чем, например, 0,1.
BIC Rb,Ra,#3 ; выровнить адрес по границе одного слова.
LDMIA Rb,{Rd,Rc} ; Прочитать 64 бита, содержащие ответ
AND Rb,Ra,#3 ; Фактор коррекции в байтах
MOVS Rb,Rb,LSL#3 ; ...теперь в битах и проверка на выравненность.
MOVNE Rd,Rd,LSR Rb ; Выделить младшую часть результата слова
; (если не выровнено)
RSBNE Rb,Rb,#32 ; get other shift amount
ORRNE Rd,Rd,Rc,LSL Rb ; combine two halves to get result
; Получить число других сдвигов
; Комбинируя двумя половина, сформировать
; результат
|
|