Thumb код в действии
Простая подпрограмма на языке C
Ниже приводится простая подпрограмма на языке C, показывающая различия между кодами ARM и Thumb. Эта подпрограмма возвращает абсолютную величину целого числа C, переданного ему как параметр.
Код на языке C:
if (x>=0) |
|
|
return x; |
else |
|
|
return -x; |
Эквивалент ARM ассемблерной версии - (исключая преамбулу):
Iabs CMP r0, #0 ; Сравнить r0 с нулем
RSBLT r0, r0, #0 ; Если r0 < 0 (меньше чем = LT), то выполнить
; r0 = 0-r0
MOV pc, lr ; Переместить Linc Register в PC (Возврат)
|
Версия Thumb ассемблирования:
CODE16 ; Директива, определяющая 16-разрядную (Thumb) команду
Iabs CMP r0, #0 ; Сравнить r0 с нулем
BGE return ; Перейти к Return если больше или равно нулю
NEG r0, r0 ; Если нет, инвертировать r0
return MOV pc, lr ; Переместить Link регистр в PC (Возврат)
|
Размеры кода для обоих версий показываются в таблице.
Таблица 1: Размер кода для подпрограммы абсолютной величины
Код |
Количество команд |
Размер (байты) |
Соотношение |
ARM |
3 |
12 |
1,0 |
Thumb |
4 |
8 |
0,67 |
Меньший размер ассемблированного кода Thumb
Сравнение, приведенное в таблице 1 показывает, что код Thumb - на 33 % плотнее кода ARM, реализующего точно такую же функцию. Обратите внимание на то, что для выполнения задачи в коде Thumb необходимо большее количество команд чем в эквиваленте ARM. Однако, поскольку формат команды Thumb - только половина длины команд ARM, то общий размер подпрограммы в коде Thumb все же меньше.
Пример кодирования вручную
Как пример кодирования вручную, рассмотрим пример преобразования двоичного значения в шестнадцатиричное :
Код ARM:
MOV r1, r0 ; r0 хранит значение для преобразования
; загрузить r1 хранимым значением
MOV r2, #8 ; Загрузить в r2 десятичное число 8
Loop: MOV r1, r1, ROR #28 ; Вращать r1 вправо на 28 и результат сохранить в r1
AND r0, r1, #15 ; Выполнить AND содержимого r1 с десятичным числом 15
CMP r0, #10 ; Сравнить r0 с десятичным числом 10 и
ADDLT r0, r0, #'0' ; если оно меньше чем 10, то
; ADD ASCII значение 0 к r0
ADDGE r0, r0, #'A' ; в ином случае (больше или равно)
; ADD ASCII значение A к r0
SWI 0 ; подпрограмма вывода char на экран
SUBS r2, r2, #1 ; Вычесть 1 из r2
BGT Loop ; и вернуться обратно к 1, если r2 все еще больше чем нуль
MOV pc, lr ; Загрузить PC содержимым Link регистра (Возврат)
|
Код Thumb:
Код ARM:
MOV r1, r0 ; Преобразуемое значение, хранящееся в r0 загрузить в r1
MOV r2, #8 ; Поместить 8 в r2
Loop1 LSR r0, r1, #28 ; Выполнить логический сдвиг r1 вправо
; на 28 мест и поместить в r0
LSL r1, r1, #4 ; Выполнить логический сдвиг r1 влево на 4 места
CMP r0, #10 ; Сравнить r0 с 10 и
BLT Loop2 ; если меньше чем 10, выполнить переход к Loop2
ADD r0, #'A'-'0'-10 ; Выполнить ADD ASCII значений A-0-10 (7) к r0
Loop2 ADD r0, #'0' ; Выполнить ADD ASCII значения 0 (48) к r0
SWI 0 ; Подпрограмма записи char на экран
SUB r2, #1 ; Вычесть 1 из r2 и,
BNE Loop1 ; если незакончено loop1,
MOV pc, lr ; загрузить PC содержимым Link регистра
; (Возврат)
|
Cоответствующие размеры ARM и Thumb кодов показаны ниже.
Таблица 2: Размеры кодов подпрограмм преобразования двоичной величины в шестнадцатиричную
Код |
Количество команд |
Размер (Байты) |
Соотношение |
ARM |
11 |
44 |
1,0 |
Thumb |
12 |
24 |
0,55 |
В данном случае код Thumb оказывается на 45% более плотным чем эквивалентный код ARM, в точно таком же алгоритме.
Таблица 3: Система команд Thumb
Мнемоника |
Команда |
Пример |
Эквивалент кода ARM |
ADC |
Сложить с переносом |
ADC Rd, Rs |
ADCS Rd, Rd, Rs |
ADD |
Сложить |
ADD Rd, Rs, Rn |
ADD Rd, Rs, Rn |
AND |
Выполнить AND |
AND Rd, Rs |
ANDS Rd, Rd, Rs |
ASR |
Арифметически сдвинуть вправо |
ASR Rd, Rs |
MOVS Rd, Rd, ASR Rs |
B |
Перейти безусловно |
B label |
B label |
BCC |
|
BCC label |
BCC label |
BIC |
Очистить бит |
BIC Rd, Rs |
BICS Rd, Rd, Rs |
BL |
Перейти и связать |
BL label |
BL label |
BX |
Перейти и обменять |
BX Hs |
BX Hs |
CMN |
Отрицательно сравнить |
CMN Rd, Rs |
CMN Rd, Rs |
CMP |
Сравнить |
CMP Rd, #Offset8 |
CMP Rd, #Offset8 |
EOR |
EOR |
EOR Rd, Rs |
EORS Rd, Rd, Rs |
LDMIA |
Загрузить множество |
LDMIA Rb!, {Rlist} |
LDMIA Rb!, {Rlist} |
LDR |
Загрузить слово |
LDR Rd, [PC, #lmm] |
LDR Rd, [PC, #lmm] |
LDRB |
Загрузить байт |
LDRB Rd, [Rb, Ro] |
LDRB Rd, [Rb, Ro] |
LDRH |
Загрузить полуслово |
LDRH Rd, [Rb, #lmm] |
LDRH Rd, [Rb, #lmm] |
LSL |
Логически сдвинуть влево |
LSL Rd, Rs, #Offset5 |
MOVS Rd, Rs, LSL #Offset5 |
LDRSB |
Загрузить байт со знаком |
LDRSB Rd, [Rb, Ro] |
LDRSB Rd, [Rb, Ro] |
LDRSH |
Загрузить полуслово со знаком |
LDRSH Rd, [Rb, Ro] |
LDRSH Rd, [Rb, Ro] |
LSR |
Логически сдвинуть вправо |
LSR Rd, Rs |
MOVS Rd, Rd, LSR Rs |
MOV |
Переместить содержимое регистра |
MOV Rd, #Offset8 |
MOVS Rd, #Offset8 |
MUL |
Перемножить |
MUL Rd, Rs |
MULS Rd, Rs, Rd |
MVN |
Переместить NOT регистр |
MVN Rd, Rs |
MVNS Rd, Rs |
NEG |
Отрицать |
NEG Rd, Rs |
RSBS Rd, Rs, #0 |
ORR |
Выполнить OR |
ORR Rd, Rs |
ORRS Rd, Rd, Rs |
POP |
Поднять регистр |
POP {Rlist} |
LDMIA R13!, {Rlist} |
PUSH |
Опустить регистр |
PUSH {Rlist} |
STMDB R13!, {Rlist} |
ROR |
Вращать вправо |
ROR Rd, Rs |
MOVS Rd, Rd, ROR Rs |
SBC |
Вычесть с переносом |
SBC Rd, Rs |
SBCS Rd, Rd, Rs |
STMIA |
Сохранить множество |
STMIA Rb!, {Rlist} |
STMIA Rb!, {Rlist} |
STR |
Сохранить слово |
STR Rd, [Rb, Ro] |
STR Rd, [Rb, Ro] |
STRB |
Сохранить байт |
STRB Rd, [Rb, Ro] |
STRB Rd, [Rb, Ro] |
STRH |
Сохранить полуслово |
STRH Rd, [Rb, Ro] |
STRH Rd, [Rb, Ro] |
SWI |
Программное прерывание |
SWI Value8 |
SWI Value8 |
SUB |
Вычесть |
SUB Rd, Rs, Rn |
SUBS Rd, Rs, Rn |
TST |
Тестировать биты |
TST Rd, Rs |
TST Rd, Rs |
Mаршрут разработки программного обеспечения
Мы рекомендуем использовать комплекта инструментальных средств разработки программного обеспечения фирмы ARM (ARM Software Development Toolkit).
|