Вместо введения. Чем ARM процессоры необычны.

Вместо введения. Чем ARM процессоры необычны.

Что такое "тумба". Два набора команд в одном процессоре.


 

Младшие версии ARM процессоров имеют 32 разрядный набор команд, ориентированный преимущественно на обработку 32-х разрядных данных. 

Высокая разрядность данных, заложенная в ARM изначально, хорошо подходит для устройств с большой вычислительной нагрузкой. "Широкие" команды дают возможность в коде одной команды реализовать достаточно сложную обработку данных, для которой в других процессорах потребуется несколько команд - например, совместить сдвиг, сумму, и перенос в другой регистр. Но с другой стороны, эти же свойства снижают применимость младших версий ARM процессоров в качестве вычислительных ядер для недорогих, встраиваемых или мобильных устройств с малоразрядной периферией, получивших сейчас большое распространение. Для реализации простой логики управления 4 байтная команда занимает слишком много места в памяти, а 32 разряда данных используются неэффективно.

Для придания современным версиям ARM процессоров большей универсальности, им добавили второй набор, уже 2 байтных команд, гораздо более эффективный по размеру кода. Набор укороченных команд называется Thumb, а набор 'стандартных' команд- ARM наборами. Несмотря на то, что 'внутри' процессора команды Thumb преобразуются перед исполнением в ARM инструкции, с точки зрения программиста эти наборы настолько отличаются, что вполне могли бы принадлежать разным процессорам. Переход от одного набора к другому может выполняться в любом месте, практически любой алгоритм можно написать либо на ARM либо на Thumb, по усмотрению программиста. Но, поскольку в Thumb наборе нет команд, требуемых для обработки исключительных ситуаций (к примеру, сброса или прерываний), любая программа требует включения фрагментов ARM. После сброса или наступления исключительной ситуации процессор принудительно переключается к исполнению команд ARM набора.

Набор Thumb, имея меньшую разрядность, оптимизирован, в его состав ввели только команды, реализующие наиболее важные операции, и он несколько ограничивает доступ к ресурсам процессора. Например, с 16 до 8 меняется число полностью доступных регистров. Некоторые команды из набора Thumb предоставляют ограниченный доступ к регистрам R8..R15, называемых в этом режиме 'верхними', или 'старшими регистрами' (high registers). Указатель стека SP (R13), регистр адреса возврата LR (R14), счетчик команд PC (R15) доступны в Thumb через специальные команды, прямой доступ к словам состояния CPRS и SPRS не предоставляется.

Программная смена набора команд происходит при выполнении двух специальных команд - "BX" 'перехода на адрес с изменением' (Branch and eXchange) и вызова подпрограммы "BLX", (Branch, Link and eXchange). Если при исполнении этих команд младший разряд адреса перехода равен 1, процессор переключится в Thumb режим, если равен 0, то в ARM режим. Последующие команды, на которые осуществляется переход, будут рассматриваться как принадлежащие выбранному набору. Эти две команды присутствуют и в Thumb и в ARM, конечно для каждого набора свои версии. 

Команды ARM режима длиной 4 байта, хранятся по адресам, кратным 4-м (0, 4, 8, 0xC и т.д.), а двухбайтные команды THUMB режима по адресам, кратным 2 (0, 2, 4...). Нетрудно заметить, что в обоих случаях последний разряд адреса равен нулю. Поэтому для реализации перехода в Thumb режим необходимо устанавливать этот бит 'принудительно', для чего к адресу прибавляют единицу. 

Пример: 

LDR R1,=TProc1 +1; ( * см. далее “Команды, которых нет”)

BX R1; переход на адрес TProc1 с изменением набора команд на Thumb.


 

В сам регистр R15 адрес загружается в любом случае с обнуленным младшим разрядом.

В отличии от команд 'BX' и 'BLX', применение 'обычных' команд 'B' и 'BL' или изменение значения регистра R15 любой командой, к смене набора команд не приводит. Поэтому в Thumb режиме +1 к каждому адресу перехода приписывать не надо, что значительно облегчает жизнь программиста.

Есть еще один способ сменить набор инструкций. Необходимо установить в нужное состояние флаг T в регистре SPSR и выполнить команду восстановления регистра CPSR из SPSR. 

Замечание: в нормальном режиме исполнения программ регистр SPSR недоступен, он есть только в некоторых привилегированных режимах. Непосредственное изменение T флага в регистре CPSR приводит к НЕПРЕДСКАЗУЕМОМУ результату.

Команды, которых нет.


 

Еще одна особенность программирования для ARM, первое время затрудняющая работу - это наличие в исходных текстах программ или листингах деассемблера таких команд или способов адресации, которые не умеет исполнять процессор и которых, соответственно, нет в его описании. Это вызвано тем, что огромное разнообразие возможных форм команд вынуждает для самых часто используемых из них применять специальные сокращенные обозначения. 

К примеру, формы автоматической адресации команды LDR вызывают немало вопросов.

Команда LDR Load Register служит для загрузки в указанный первым операндом регистр 32-х разрядного слова из памяти. Адрес памяти, откуда происходит загрузка, может вычисляться процессором 9-ю различными, порой довольно сложными способами. Подробно способы вычисления адреса будут рассмотрены далее, но сейчас отметим, что все они требуют, чтобы в качестве базового при вычислении адреса использовалось значение, хранящееся в одном из регистров R0:R15.


 

Самая простая форма вычисления адреса памяти для команды LDR такова:


 

LDR Rd, [Rm,#смещение]

- загрузить в Rd значение хранящееся по адресу Rm + смещение. 


 

При нулевом смещении допустима такая упрощенная запись:


 

LDR Rd, [Rm] ; - синоним LDR Rd, [Rm, #0]


 

Получается, что если мы хотим при помощи самой простой формы команды LDR загрузить в регистр R1 число 0x22334455, нам нужно:


 

1. Сохранить это число в памяти (при компиляции, например)

2. Загрузить в любой регистр, скажем, в R2 адрес этого числа

3. Выполнить LDR R1,[R2]


 

А как нам выполнить пункт 2? Как нам загрузить в регистр 32 битный адрес? Выходом служит вычисление адреса данных относительно состояния регистра R15 (счетчик команд, PC), значение которого всегда определенно и на текущий момент известно – оно равно адресу выполняемой команды. Надо только учитывать, что при любом чтении из R15 в режиме ARM возвращается значение равное (адресу_текущей_команды + 8)*. 


 


 

thisAddr: LDR R1,[R15, #SourceData - thisAddr - 8] ; коррекция на 8

...

SourceData: DD 0x22334455 ; недалеко в памяти данные 

; это работающий пример загрузки в регистр R1 числа 0x22334455 


 


 

Конечно, это сложно и неудобно. Для упрощения жизни программистов у ARM ассемблера есть специальные формы автоматической адресации (здесь под ассемблером подразумевается программа, переводящая исходный *.asm текст в объектный код):


 

-------------------------------------------------------------------------------

* Примечание: в Thumb чтение R15 дает значение, равное (адресу_текущей_команды + 4)


 

1. Для команд обмена регистра с памятью допустимо вторым операндом указывать непосредственно адрес, к содержимому которого необходимо обратиться. Выбор R15 в качестве базового регистра и вычисление смещения будут выполнены ассемблером автоматически, гарантируя правильную адресацию.


 

LDR R1, SourceData; прочитать значение по адресу SourceData в регистр

STR R1, SourceData; записать из регистра в адрес SourceData


 

SourceData: DD 0x22334455; адрес недалеко в памяти 


 

2. Для загрузки в регистр конкретного значения можно указать вторым операндом не адрес хранения числа, а непосредственно требуемое число и добавить перед ним знак '='. Тогда все необходимые действия, вплоть до размещения числа в памяти, будут выполнены ассемблером автоматически, гарантируя загрузку требуемого значения.


 

LDR R1,=0x22334455 ; здесь R1 := 0x22334455


 

Или, как вариант загрузки произвольного 32 разрядного адреса:

...

Label_1:

LDR R1, =Label_1; здесь R1 := адресу Label_1 (адрес тоже Число) 

...

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


 

LDR Rd, [PC, #offsetDataStore];

...

DataStore: DD 123456789;


 

Это накладывает ограничения на использование автоматической адресации. Во первых, смещение 12 разрядное (для команд LDRD STRD LDRH STRH LDRSH LDRSB даже 8 разрядное), то есть для загружаемых данных должно найтись место в пределах +/- 4095 (+/- 255) адресов от команды. Во вторых, понятно, что при сохранении данных командой STR надо убедится, что мы не пытаемся записывать в ПЗУ, или, при отладке, мы не должны писать в сегмент кода (запись в него запрещена). Но если в KEIL создать для имитации ОЗУ сегмент данных с разрешением записи, попытка автоматической адресации данных за пределы сегмента кода дает ошибку при ассемблировании: 

error A20: INVALID SIMPLE RELOCATABLE EXPRESSION. 


 

В некоторых случаях надо быть готовым к тому, что ассемблер заменит конструкцию LDR Rn,=data на команду MOV Rn, #data. Это произойдет, если загружаемое значение можно представить как любое 8 разрядное число от 0x00 до 0xff, циклически сдвинутое на произвольное четное количество разрядов (0,2,4...30) внутри 32 разрядного регистра (просто, не правда ли? =), в этом случае будет произведена оптимизация, и вместо ожидаемой команды LDR будет вставлена команда 

MOV Rn,#data

где #data - так называемые непосредственные данные. Подробнее о них - дальше, в разделе addressing_mode.


 

IDA умеет 'сворачивать' команды LDR обратно в формы автоматической адресации, но тем не менее не прячет данные, которые участвуют в такой операции:


 

LDR PC, =loc_A000009C; свернутая форма

; -------------------------------------------------

off_A0000004 DCD loc_A000009C ; это те данные, которые грузятся


 

Еще две 'команды', которые встречаются в программах, но которые не умеет исполнять процессор:

ADR Rx, Address ; - загрузить в Rx указанный относительный адрес. Реально это команда превращается ассемблером в команду ADD Rx,PC,#xx или SUB Rx,PC,#xx, вычисляя нужное значение прибавлением или вычитанием смещения от PC. Очевидное ограничение - применимое для написания программ смещение между адресом команды и загружаемым адресом не более +/-255 байт. 

RET – В действительности это команда MOV R15,R14.

Еще один вариант “автоматической” команды – MOVL Rx,#data

В Thumb режиме максимальное число, загружаемое в регистр командой mov Rx,#data равно 255. При необходимости загрузить большее число, применяют команду movl Rx,#data, которая автоматически будет заменена на пару команд: 

mov Rx,#data
lsl Rx,Rx,#shift

или

mov Rx,#data1

add Rx,#data2

в зависимости от того, каким образом можно представить число, которое необходимо загрузить. В отличие от IDA, Keil такую форму команды не понимает 

Типы данных и размещение в памяти. Дамп программы.


 

Для ARM процессора используются данные четырех типов: байт, полуслово, слово и двойное слово. Некоторые дополнительные команды версии ARM9E используют 32 разрядное значение в регистре как два упакованных 16 разрядных полуслова со знаком.

БАЙТ (byte),

8 разрядов, может храниться по произвольному адресу. Для чтения и записи используются команды LDRB,LDRSB, STRB.


 

Пример на ассемблере:

...

org 0x20

MyByte1: DB 0x1 ; по адресу 0x20 поместим байт данных равный 0x1

MyByte2: DB 0x2 ; по адресу 0x21 поместим байт данных равный 0x2

MyByte3: DB 0x3 ; по адресу 0x22 поместим байт данных равный 0x3

MyByte4: DB 0x4 ; по адресу 0x23 поместим байт данных равный 0x4

MyByte5: DB 0x5 ; по адресу 0x24 поместим байт данных равный 0x5

...

Не стоит забывать, что в ARM процессорах подразумевается 32 разрядная шина данных. Поэтому дамп предыдущего примера в отладчике keil, показывающего память в виде 32 разрядных слов, покажет такой результат: 


 

дамп keil:

0x00000020 04030201 - байты объединены в слово.

0x00000024 00000005 - продолжение в следующем слове, адрес 0x24. 


 

Но дамп IDA покажет:

0x00000020 01 02 03 04 05 - обычный порядок байт (данные не объединены в слова)

ПОЛУСЛОВО (halfword),

16 разрядов, адрес хранения должен быть четным (адрес[0] = 0). Команды LDRH,LDRSH, STRH


 

org 0x20

MyHalf1: DW 0x1111; по адресу MyHalfW поместим полуслово равное 0x1111

NextHalf: DW 0x2222; еще полуслово

NextHalf: DW 0x3333; еще полуслово


 

дамп keil:

0x00000020 22221111 

0x00000024 00003333 

дамп IDA:

0x00000020 11 11 22 22 33 33 

СЛОВО (word),

Основной тип данных, 32 разряда. Адрес должен быть выравнен кратно 4м байтам (адрес[0]=0; адрес[1]=0). Команды LDR, STR и другие.


 

org 0x20

MWord: DD 0x12345678 ; по адресу MWоrd поместим слово равное 0x12345678


 

дамп keil:

0x00000020 12345678 

дамп IDA:

0x00000020 78 56 34 12 ; IDA показывает (по умолчанию) вместо слов байты

Все команды обработки данных, например ADD, оперируют с 32 разрядными словами. Исключением являются дополнительные команды арифметики с насыщением. Команды передачи данных оперируют с 8, 16, 32 или 64 разрядными значениями. 

Все перечисленные типы данных могут рассматриваться как беззнаковые, так и как значения со знаком. При загрузке в 32 разрядные регистры байт или полуслов из памяти специальными командами LDRB, LDRH происходит автоматическое дополнение ведущими нулями, а по команде LDRSB,LDRSH происходит расширение знакового разряда. 

...

start: LDRB R3,dataByte ;в R3 загрузится 0x00000081- дополнение нулями 

LDRSB R4,dataByte ;в R4 загрузится 0xffffff81- расширение знака 

LDRSB R4,dataByt1 ;в R4 загрузится 0x0000007E- расширение знака 

dataByte: DB 0x81 ; Однобайтовое значение

dataByt1: DB 0x7E ; Однобайтовое значение

...

ДВОЙНОЕ СЛОВО (dword),

64 разряда, адрес должен быть выравнен кратно 4м байтам (адрес[0]=0; адрес[1]=0). 

Команда LDRD Rd,<addressing_mode> загружает из памяти два последовательных регистра, Rd и Rd+1, команда STRD сохраняет их. Для этой команды в качестве Rd можно указывать только четные регистры R0 R2 R4 R6 R8 R10 или R12.


 

Работа с дампом программы в IDA

 

В самом начале работы прошивка телефона выглядит как последовательность байт - дамп памяти. И всегда интересно, где нажать 'C', чтобы получить осмысленный результат в виде ассемблерной программы. Что можно предпринять, чтобы достичь желаемого? Рассмотрим для примера участки дампа прошивки Siemens CX70v50

Во первых, участок такого вида: 

BCORE:A000087F DCB 0

BCORE:A0000880 DCB 0x53 ; S

BCORE:A0000881 DCB 0x49 ; I

BCORE:A0000882 DCB 0x45 ; E

BCORE:A0000883 DCB 0x4D ; M

BCORE:A0000884 DCB 0x45 ; E

BCORE:A0000885 DCB 0x4E ; N

BCORE:A0000886 DCB 0x53 ; S

BCORE:A0000887 DCB 0


 

поощряет нажать клавишу 'A' для создания строки, желательно на адресе, кратном 4 (здесь A0000880), так как чаще всего к строкам обращаются командами загрузки 32 разрядных регистров, или командами мультирегистровой загрузки, данные для которых выравниваются кратно 4 байтам.

Во вторых, если явных признаков строк или данных нет, вспомним, что команды набора ARM четырехбайтные, выравнены в памяти кратно 4, поэтому не могут начинаться с адресов иных, чем с шестнадцатеричными цифрами 0, 4, 8 или C в конце.

В третьих, подпрограммы - основа любой программы, поэтому стоит обратить внимание на участки, предположительно, кода в которых на границе слов (4х байт) встречается команда с кодом E92Dxxxx - команда STMFD SP! ,{xx} сохранения регистров в стек. 


 

BCORE:A000242C ; --------------------------

BCORE:A0002430 DCB 0x38 ; \ 1й байт

BCORE:A0002431 DCB 0x40 ; | 2й байт

BCORE:A0002432 DCB 0x2D ; | 3й команда E9 2D 40 38

BCORE:A0002433 DCB 0xE9 ; / 4й

BCORE:A0002434 DCB 1

BCORE:A0002435 DCB 0x50 ; 

Поместим курсор на первом байте команды (здесь – равен 0x38). Вот что получилось после нажатия 'C': 

A0002430 ; -----------------------------------------

A0002430 STMFD SP!, {R3-R5,LR} ;сохранить регистры и адрес возврата

A0002434 MOV R5, R1

A0002438 MOV R4, R0

A000243C BL sub_A0002574

A0002440 BL sub_A00027E8

A0002444 CMP R0, #0

A0002448 LDREQ R1, =0x1C200

A000244C MOVEQ R0, #3

A0002450 LDMEQFD SP!, {R3-R5,LR}

A0002454 BEQ sub_A0002478

A0002458 MOV R1, R5

A000245C MOV R0, R4

A0002460 BL sub_A00025B4

A0002464 BL sub_A0002E40

A0002468 CMP R0, #0

A000246C LDMNEFD SP!, {R3-R5,LR}; 

A0002470 BNE loc_A00063B0 ; 

A0002474 LDMFD SP!, {R3-R5,PC}; конец подпрограммы


 

Видим, что это вполне осмысленная подпрограмма, нажмем 'P' на ее начале и подтвердим создание.

Гораздо реже подпрограмма ARM режима начинается с команды сохранения одиночного регистра LR в стек: 

STR LR, [SP,#-4]! (E5 2D E0 04) :


 

A0824258 DCB 4 \

A0824259 DCB 0xE0 ; |

A082425A DCB 0x2D ; | STR LR, [SP,#-4]! 

A082425B DCB 0xE5 ; /

A082425C DCB 0xB8 ; 

A082425D DCB 0xFD ; 

A082425E DCB 0xFF ;


 

Результат 'C':

A0824258 STR LR, [SP,#-4]!

A082425C BL sub_A0823944

A0824260 CMP R0, #0

A0824264 BEQ loc_A0824278

A0824268 LDR R1, [R0,#4]

A082426C LDR R2, =0x73617072

A0824270 CMP R1, R2

A0824274 LDREQ PC, [SP],#4

A0824278 loc_A0824278 ; CODE XREF: A0824264_j

A0824278 MOV R0, #0

A082427C LDR PC, [SP],#4


 

Большинство команд ARM режима обычно имеют старший ниббл (полубайт, тетрада) равный 'E', так как это соответствует признаку 0b1110 - Always, безусловное исполнение команды. Если какой- либо участок памяти выглядит подобно этому (обратите внимание на расположение байтов с E в начале):


 

A00021C0 28 10 94 E5 63 03 D4 E1-29 00 00 EB 41 00 00 EA 

A00021D0 4B 10 93 E5 48 03 D3 E1-4D 30 A0 E1 41 20 A0 E3 

A00021E0 54 02 00 EB 4F 00 50 E3-56 00 00 0A 2E 10 A0 E1 


 

то вероятность того, что это код ARM, очень велика.


 

Адреса команд Thumb всегда четные. Команды Thumb более компактны, и код имеет более равномерный "спектр", поэтому отличить код от данных сложнее. Зато 99% подпрограмм начинаются с команды PUSH {regs,LR}, код которой B5 xx, где xx – маска сохраняемых регистров. 


 

Попробуем найти вероятное начало Thumb подпрограммы в таком коде:

A1714F2B DCB 0x68 ; h

A1714F2C DCB 0x40 ; @

A1714F2D DCB 0x18

A1714F2E DCB 0x40 ; @

A1714F2F DCB 0x68 ; h

A1714F30 DCB 0x70 ; p

A1714F31 DCB 0x47 ; G

A1714F32 DCB 0x80 ; A \<= возможно здесь начало Thumb подпрограммы?

A1714F33 DCB 0xB5 ; ¦ / 

A1714F34 DCB 0xFF

A1714F35 DCB 0xF7 ; ?

A1714F36 DCB 0xD6 ; a

A1714F37 DCB 0xFF

A1714F38 DCB 0


 

Переключим IDA в режим разбора Thumb команд. Для этого нажмем alt+G и в появившемся диалоге присвоим биту 'T’ значение 1.

Нажмем 'P' на адресе (четном) первого байта команды и посмотрим результат:


 

sub_A1714F32

A1714F32 PUSH {R7,LR}

A1714F34 BL sub_A1714EE4

A1714F38 CMP R0, #0

A1714F3A BEQ loc_A1714F62

. . . . .


 

A1714F5A CMP R0, R1

A1714F5C BNE loc_A1714F62

A1714F5E MOV R0, #1

A1714F60 POP {R7,PC}


 

Наша догадка верна. Если бы мы ошиблись, всегда можно нажать 'U' для отмены.

Для автоматического поиска байта или их последовательности можно вызвать диалог, нажав alt+b .

 

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


 

CODE2:A0CE080F DCB 0

CODE2:A0CE0810 DCB 0x1F

CODE2:A0CE0811 unk_A0CE0811 DCB 0xB5 ;DATA XREF: CODE2:off_A0CE09BC

CODE2:A0CE0812 DCB 0x81 ; Á

CODE2:A0CE0813 DCB 0x68 ; h


 

Очевидно, что IDA обнаружила обращение по нечетному адресу, значит, возможно идет обращение к Thumb подпрограмме с адресом A0CE0810.


 


 


 



 

ИСКЛЮЧЕНИЯ


 

Исключения (исключительные ситуации) - события, приводящие к прерыванию выполнения процессором текущей задачи и передачи управления по фиксированному адресу, для обработки причин исключения, таких как программные или аппаратные прерывания, отказ доступа к памяти или попытки исполнения неизвестных команд. 


 

Состояние регистров процессора перед обработкой исключения должно быть сохранено, чтобы исполнение основной программы могло быть нормально продолжено после обработки исключения. При возникновении исключения управление передается по адресу, указанному в третьем или четвертом столбце нижеследующей таблицы, в зависимости от того, установлен или нет режим ‘верхних векторов’ и процессор переходит в режим, указанный во втором столбце. Адреса перехода после сброса процессора соответствуют третьему столбцу таблицы, но процессор может быть сконфигурирован для использования старших адресов.


 

ARM поддерживает семь типов исключений. 


 

Тип Режим адрес адрес резерв.


 

Сброс supervisor 0x00000000 0xffff0000

Неизвестная инструкция undefined 0x00000004 0xffff0004

Программное прерыв. (SWI) supervisor 0x00000008 0xffff0008

Отказ считывания команды Abort 0x0000000c 0xffff000c

Отказ доступа к данным Abort 0x00000010 0xffff0010

Ошибка адреса (устарело) Address Except. 0x00000014 0xffff0014

IRQ Irq 0x00000018 0xffff0018

FIQ Fiq 0x0000001C 0xffff001C

 

Исключение "ошибка адреса" - выход за пределы 26 разрядного адреса, в современных версиях процессоров не происходит. Поведение современных версий при переполнении счетчика команд в документации описывается как непредсказуемое (unpredictable).


 

При наступлении исключения процессор исполняет команды ARM, в регистр R14 заносятся адрес возврата, в SPSR состояние CPSR прерванной задачи. В биты CPSR [4:0] заносится код режима. Запрещается обычное прерывание, а если наступившее исключение - сброс или FIQ, запрещается быстрое прерывание.


 

Для возврата из обработки необходимо скопировать SPSR_xxx в CPSR и R14_xxx в R15, где _xxx - соответствует банку исключения. 

Рекомендуемая последовательность команд для начала и завершения обработки исключения:

sub r14,r14,#4 ;сдвинуть указатель стека вниз

stmfd sp!, {<список_регистров>,r14}

...... обработка

ldmfd sp!,{ <список_регистров>,r15}^


 

Модификатор '^' в данном случае означает восстановление регистра CPSR из SPSR.


 

Reversing: Для реверсинга интересны фиксированные адреса обработчиков исключений 


 



 

РЕЖИМЫ ПРОЦЕССОРА


 

ARM процессор 4-й версии и старше может находиться в одном из семи 'режимов процессора' 


 

РЕЖИМ ОПИСАНИЕ

------------------------------------------------------------------------- 

User usr ! Пользовательский. Стандартный режим исполнения программ

FIQ fiq ! Поддержка высокоскоростной передачи данных или

! канальный процесс.

IRQ irq ! Используется для обычной обработки прерываний.

Supervisor svc ! Управляющий. Защищенный режим для операционной системы. 

Abort abt ! Отказ. Применяется для виртуальной памяти и/или защиты 

! обычной памяти

Undefined und ! Неопределенный. Поддержка программной эмуляции

! аппаратного сопроцессора. 

System sys ! Исполнение привилегированных задач операционной системы.

----------------------------------------------------------------------- 

Изменение режимов может происходить под управлением программы, в результате внешних прерываний или при наступлении других исключительных ситуаций. Большая часть программ выполняется в пользовательском режиме. В этом режиме программе недоступны некоторые защищенные ресурсы системы и невозможна смена режима, кроме как в случае наступления исключительной ситуации.

Остальные, кроме пользовательского, режимы известны как Привилегированные.

При этом все ресурсы доступны и возможна свободная смена режимов. Пять из привилегированных режимов известны как режимы обработки исключительной ситуации:


 

FIQ 

IRQ

Supervisor

Abort

Undefined


 

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

Оставшийся привилегированный режим- Системный, и он присутствует в процессорах 4-й и старше версий. Только в него попадают не в результате исключения и он имеет набор регистров совпадающий с пользовательским режимом. Тем не менее, это привилегированный режим и он не имеет ограничений пользовательского режима. Он используется для выполнения заданий операционной системы, которым должны быть доступны защищенные системные ресурсы. 

 



 

РЕГИСТРЫ


 

Всего ARM процессор имеет 37 регистров шириной 32 разряда, из них тридцать один регистр называют регистрами общего назначения R0..R15. Еще 6 регистров являются регистрами состояния CPSR и SPSR. Они также 32 разрядные, но используется в них только по 12 бит.

Регистры объединяются в семь частично перекрывающихся банков регистров. Каждый банк соответствует одному из семи режимов процессора.


 

------------------------- режимы ----------------------------------------

User System Superv. Abort Undef. Interr. Fast Interr.

--------------------- банки регистров ------------------------------------

R0 R0 R0 R0 R0 R0 R0

R1 R1 R1 R1 R1 R1 R1

R2 R2 R2 R2 R2 R2 R2

R3 R3 R3 R3 R3 R3 R3

R4 R4 R4 R4 R4 R4 R4

R5 R5 R5 R5 R5 R5 R5

R6 R6 R6 R6 R6 R6 R6

R7 R7 R7 R7 R7 R7 R7

R8 R8 R8 R8 R8 R8 R8_fiq

R9 R9 R9 R9 R9 R9 R9_fiq

R10 R10 R10 R10 R10 R10 R10_fiq

R11 R11 R11 R11 R11 R11 R11_fiq

R12 R12 R12 R12 R12 R12 R12_fiq

R13 R13 R13_svc R13_abt R13_und R13_irq R13_fiq

R14 R14 R14_svc R14_abt R14_und R14_irq R14_fiq

R15 R15 R15 R15 R15 R15 R15

CPSR CPSR CPSR CPSR CPSR CPSR CPSR

SPSR_sv SPSR_abt SPSR_un SPSR_ir SPSR_fiq

 

Как видно из таблицы, регистры пользовательского и системного режимов полностью совпадают. 

Регистры R0..R12, R15(PC), CPSR (состояния) общие для всех режимов, за исключением FIQ. 

В режимах обработки исключений есть дополнительное, для каждого режима отдельное, так называемое 'сохраненное слово состояния процессора' SPSP и свои регистры R13(SP) R14(LR). 

В режиме FIQ ввели дополнительно свой независимый набор регистров R8..R12. Это позволяет приступить к обработке быстрого прерывания сразу, не заботясь о сохранении контекста прерванной задачи, используя только 'свои' регистры и быстро вернуть управление после завершения обработки.


 

Регистры общего назначения, используемые особым образом

R13, R14, R15


 

Несмотря на то, что они могут участвовать как обычные регистры в операциях, почему их и включают в число регистров общего назначения, их специализация обязательно должна учитываться при написании программ. Особенно это относится к регистру R15 (PC). 

Регистр R13 (SP)

обычно используется в качестве указателя стека (SP). В ARM режиме нет команд, использующих этот регистр особым образом, в наборе Thumb такие команды есть – push и pop. Свой R13 есть в каждом из банков соответствующих обработке исключений. 



 

Регистр R14 (LR).

известен как регистр связывания Link registr (LR) и в двух случаях используется особым образом: 


 

Первый случай. В любом режиме процессора ассоциированный с ним экземпляр регистра R14 используется для сохранения адреса возврата из подпрограммы. Когда подпрограмма вызывается командами BL или BLX, в R14 заносится адрес следующей команды, то есть адрес возврата. Возврат производится копированием R14 в R15 (PC). Это достигается одним из двух стандартных способов:

- Исполнением для возврата команд подобных: 

MOV R15,R14 (синоним - RET)

BX LR

которые копируют значение регистра R14 в R15 


 

- Или, при входе в подпрограмму можно сохранить R14 вместе с другими регистрами в стек такой командой:

STMFD SP!,{<сохраняемые регистры>,LR}

и восстановить сохраненное из R14 значение в R15, используя соответствующую команду при возврате:

LDMFD SP!,{<восстанавливаемые регистры>,PC} 


 

Еще один способ организации подпрограмм:

STR LR, [SP,#-4]! ;сохранить LR в стек

LDR PC, [SP],#4 ;восстановить из стека в PC 


 

Второй случай специального использования R14. Когда происходит исключение, в связанном с режимом исключения экземпляре R14 устанавливается адрес возврата из обработки исключения (для некоторых исключений, сдвинутый на небольшую величину). 

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

------Замечание:------

Если возможны вложенные исключения, специальные применения LR могут конфликтовать. К примеру, мы обрабатываем прерывания и находимся в IRQ режиме. Если при этом разрешить прерывания и будет получено вложенное прерывание, значение хранимое в R14 будет переписано новым адресом. Системный программист должен внимательно следить за тем, чтобы R14 не содержал незаменимых данных, когда разрешаются вложенные исключения.

--------------------------

Регистр R15 (PC)

используется в ARM архитектуре в качестве счетчика команд. 

При записи в него нового значения, происходит переход по адресу равному этому значению. 

Для версий архитектуры, поддерживающих Thumb (T вариант) нулевой разряд адреса игнорируется и всегда записывается нулем. Этот бит используется, как уже было описано выше, для смены набора команд специальными командами.

Если подразумевается переход на инструкцию ARM режима, все команды которого хранятся по адресам кратным 4, два самых младших разряда адреса должны быть 0, иначе результат непредсказуем. 

При чтении регистра R15 в ARM режиме, в регистр результата попадает значение, равное: адресу команды чтения + 8. 


 

thisAddr: MOV R1,R15 ; R1:= R15+8 (thisAddr+8)


 

Исключением из этого правила является сохранение R15 командами STR или STM. Они могут сохранять значение R15 как со смещением 8 подобно остальным инструкциям, либо со смещением 12. 

При чтении регистра R15 в Thumb режиме, в регистр результата попадает значение, равное: адресу команды чтения + 4. 



 

Регистры состояния

Регистр состояния текущей программы CPSR

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


 

Сохраненный регистр состояния программы SPSR

имеют все режимы исключений, он используется для резервирования значения CPSR прерванной задачи при наступлении исключительной ситуации. Свой SPSR есть в каждом из соответствующих банков. Режимы Пользовательский и Системный не являются режимами обработки исключительной ситуации и такого регистра не имеют.


 

Назначение разрядов регистров состояния:


 

31 30 29 28 27 ! 26 ... 8 ! 7 6 5 ! 4...0

----------------------------------------------------------

N Z C V Q ! DNM(RAZ) ! I F T ! M[4:0]

----------------------------------------------------------


 

N - Negative Z - Zero C - Carry V - oVerflow

- биты, известные, как флаги результата исполнения команд, или просто флаги. 


 

Флаги из CPSR могут проверяться перед исполнением некоторых команд и определять будет ли исполнятся эта команда, то есть служат для организации условного исполнения программ (об этом более подробно позже).

Флаги изменяют состояние при:

- Исполнении команд сравнения CMN, CMP, TEQ, TST - в любом случае.

- Исполнении арифметических, логических команд и команд копирования, у которых регистр назначения не R15, если применена специальная форма команды 
(см. {S} модификатор). 

назначение флагов N Z C V

Они устанавливаются в единицу в следующих случаях:


 

N - negative, если 31 (старший, знаковый) разряд в результате выполнения операции равен 1, то есть результат - отрицательное число.


 

Z - zero, если результат операции равен 0, или как признак 'равно' при операции сравнения


 

С - carry, перенос, изменяется в следующих случаях:

1. если операции сложения, включая операцию сравнения CMN дает переполнение результата (результат больше 0xFFFFFFFF) C:= 1, иначе 0.

2. если операция вычитания, включая операцию сравнения CMP, дают 'заем' - то есть вычитаемое число больше уменьшаемого и разность отрицательна, 'C' устанавливается в 0, иначе в 1. (Именно так, в 0 при займе, в 1 если его нет!).

3. при операциях сдвига C устанавливается в значение последнего бита, выдвинутого за пределы сдвигаемого регистра. 


 

V - overflow, меняет значение в 1 если в результате операций сложения/вычитания происходит переполнение, в то время когда операнды и результат являются целым со знаком в форме 'дополнение до двух'.

Флаги также могут быть изменены также другими способами:

- исполнением команды MSR, которая записывает новое значение в CPSR или SPSR

- исполнением MRC, когда целевым регистром является R15. Эта инструкция дополнительно переносит флаги результатов команд из сопроцессора в ARM процессор.

- Исполнение некоторых вариантов команды LDM. Эти варианты копируют SPSR в CPSR и в основном используются для возврата из обработки исключения.

Q флаг.

В варианте ARM 5 E архитектуры и более старших, бит[27] CPSR известен как Q флаг, используемый для индикации различных переполнений операций DSP.

В 9E версии процессора также используется в SATURATED формах команд обработки данных, к примеру, QADD, QDADD и т д.

I, F, T и M[4:0]

Младшие 8 разрядов регистров статуса , включающие I, F, T и M[4:0], вместе называются контрольными битами. Программный доступ к ним возможен только при нахождении процессора в привилегированном режиме.

 

I = 1 запрещает прерывания

F = 1 запрещает быстрые прерывания


 

T бит должен быть 0 в Thumb несовместимых версиях процессора. 


 

В 'T' вариантах процессора: 


 

T = 0 процессор находится в режиме исполнения ARM команд

T = 1 процессор находится в режиме исполнения Thumb команд

Биты режима процессора M[4:0]:


 

значение режим 

------------------------

0b10000 user 

0b10001 FIQ

0b10010 IRQ

0b10011 supervisor

0b10111 Abort

0b11011 Undefined

0b11111 System


 

Остальные разряды регистров статуса зарезервированы для последующих модификаций. Программист должен внимательно следить за тем, чтобы эти биты не изменялись программой. Иначе это может привести к непредсказуемому поведению программы на будущих версиях процессора. 


 

Как заставить команду изменять флаги. {S} модификатор.


 

Большинство из команд имеют как стандартную форму, сохраняющую значения флагов, так и форму, изменяющую значение флагов в зависимости от результата операции, получаемую добавлением S к мнемонике команды. 


 

Пример:

...

MOV R0, #0; флаг Z не изменится, форма команды простая

MOV R0, #1; флаг Z не изменится, форма команды простая

MOVS R0,#0; флаг Z := 1, форма команды с S

MOVS R0,#1; флаг Z := 0, форма команды с S

...

Замечание: Если вы хотите, чтобы логические и арифметические операции изменяли значения флагов результата, к ним необходимо применять специальный модификатор. Это отличает язык ассемблера ARM от большинства других, где флаги изменяются “по умолчанию”.


 



 

Как использовать флаги. Модификаторы проверки условий <cond>


 

Мы уже обсудили, как модификатор S, добавленный к команде, заставляет ассемблер заменить команду, не изменяющую флаги, ее вариантом который может приводить к изменению флагов по результату выполнения. 

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


 

Пример:

SUBS R0, R0, #1; Уменьшить R0 на 1, установить флаги по результату 

ADDEQ R1, R1, #1; Если предыдущей командой флаг Z установлен в 1, увеличить R1 на 1 


 

Эти модификаторы изменяют старшие биты [31:28] кода команды, значение в которых должно соответствовать состоянию флагов в момент исполнения. 

Есть одно особое состояние этих бит, когда все они равны 1 (0b1111). В этом случае их действие зависит от версии процессора. В версиях до 3 это соответствует тому, что команда никогда не исполняется. В 3 и 4 версиях это значение неприменимо. Начиная с 5 версии, такое значение соответствует различным дополнительным командам, исполнение которых уже не может зависеть от состояния флагов. 

Еще одно важное значение 0b1110 - Always, исполнение команды в любом случае, независимо от состояния флагов.


 

Биты Модификатор Условие Значение флагов


 

0000 EQ Равно Z = 1

0001 NE Не равно Z = 0

0010 CS/HS перенос/беззнак больше или равно C = 1

0011 CC/LO Нет переноса/беззнаковое меньше C = 0

0100 MI Минус/отрицательное N = 1

0101 PL Плюс/положительное или нуль N = 0

0110 VS Переполнение V = 1

0111 VC Нет переполнения V = 0

1000 HI Беззнаковое больше C = 1 Z = 0

1001 LS Беззнаковое меньше или равно C = 0 Z = 1

1010 GE Больше или равно, со знаком N = V

1011 LT Меньше чем, со знаком N != V

1100 GT Больше чем, со знаком Z=0 N=V

1101 LE Меньше или равно, со знаком Z=1 or N!=V

1110 AL Безусловное выполнение

1111 ---Зависит от версии процессора---


 


 

Reversing: Мы уже упоминали, что большинство команд набора ARM не проверяют условий и начинаются с байта 'E*' (Always) и выравнены по адресам, кратным четырем, что визуально облегчает их опознание.


 



 

Вычисляемые операнды, методы адресации данных ARM набора.


 

Для изучения команд ARM набора надо понимать такие базовые понятия, как: 

- правила вычисления значения непосредственных операндов <immediate>, которые хранится внутри кода команды.

- правила вычисления универсальных операндов <shifter_operand>, к которым может применятся операция сдвига.

- а также различные способы вычисления адреса для операций с памятью. 

Непосредственный операнд <immediate>


 

Первое понятие, встречающееся в командах ARM набора, так называемый, непосредственный операнд: 


 

#<immediate>


 

Это число, хранящееся внутри кода команды, в виде 8 разрядного базового значения и 4 разрядной величины сдвига. 

Значение непосредственного операнда вычисляется так: берется упомянутое 8 разрядное число (от 0x00 до 0xff), и оно циклически (по кольцу) сдвигается на некоторое четное количество разрядов (0,2,4...30) внутри 32 разрядного регистра. Величина сдвига получается умножением 4-х разрядного значения на 2 и может быть нулевой. Остальные двадцать четыре разряда, за пределами сдвинутых в новое положение восьми разрядов исходного числа, заполняются нулями.

Конечно, в виде непосредственного операнда можно представить далеко не всякое 32 разрядное число. 

К примеру, возьмем как исходный байт число 0xFF. Сдвигая, производным от него можно получить:


 

сдвиг, разрядов получившееся значение

0 0xff

на 2 0x3fc

на 4 0xff0

на 6 0x3fc0

на 8 0xff00

на 10 0x3fc00

на 12 0xff000

и так далее, до 0xff000000 и даже, сдвинув еще больше по кольцу,0xFC000003, 0xF000000F, 0xC000003F -соответственно, все это допустимые значения для того, чтобы представить их как непосредственный операнд. А числа 0x1ff, 0x4fc или 0x100203 получить сдвигом восьмиразрядного числа нельзя.

 

Еще раз обратим внимание, сдвиг на четное число разрядов. К примеру, значение 0x1fe, полученное сдвигом 0xFF на 1, в виде непосредственного операнда также представлено быть не может.

В качестве базового для сдвига, как уже говорилось, можно взять любое число от 0 до 0xFF.

Напомним, все, что здесь сказано, относится к ARM режиму. 


 



 

Универсальный операнд <shifter_operand>

В документации на KEIL его называют Flexible Operand или Op2


 

<shifter_operand> бывает трех видов:


 

#<immediate> - непосредственный операнд

<Rn> - регистровый операнд

<Rn>, ShiftMode, Shift - регистровый операнд со сдвигом


 

Значение такого операнда (регистрового со сдвигом) вычисляется следующим образом:

В качестве исходного берется содержимое регистра общего назначения <Rn> , затем к нему применяется один из пяти типов сдвигов. Величина сдвига может быть указана либо непосредственно в команде, либо как ссылка на другой регистр общего назначения.

Пять типов сдвига


 

Здесь будут описаны действия, соответствующие сдвигу конкретного типа на один разряд. Последовательно сдвигая по этим правилам несколько раз, можно получить сдвиги на любую требуемую величину от 1 до 32 разрядов для всех типов, кроме RRX, для которого применим сдвиг только на один разряд, и для которого величина сдвига в команде не указывается.

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

LSL

- логический сдвиг 32 разрядного числа влево, в младший разряд помещается 0, старший разряд, выдвигаясь за пределы регистра, теряется, но его значение сохраняется в флаге C.


 

LSR

- логический сдвиг 32 разрядного числа вправо, в старший разряд помещается 0, младший разряд, выдвигаясь за пределы регистра, теряется, но его значение сохраняется в флаге C.


 

ASR

- арифметический сдвиг 32 разрядного числа вправо, старший разряд устанавливаются в значение знакового разряда (31 бита) исходного числа (1 для отрицательного, 0 для положительного), младший разряд, выдвигаясь за пределы регистра, теряется, но его значение сохраняется в флаге C.


 

ROR

- циклический сдвиг 32 разрядного числа вправо 'по кольцу', в старший разряд помещается значение, выдвинутое из младшего, одновременно значение младшего разряда в флаге C.


 

RRX

- циклический правый сдвиг через флаг ‘C’, сдвиг вправо 'по кольцу' в псевдо 33 разрядном регистре, образованном 32 разрядным регистром и значением флага C в качестве 33-го разряда. В старший разряд помещается значение из флага C, в флаге С сохраняется значение младшего разряда.


 


 


 

Одиннадцать форм <shifter_operand>:


 

Полный список возможных видов этого типа операндов

#<immediate>

- этот вид мы уже рассматривали. 

<Rn>

Значение, хранимое в 32 разрядном регистре R0-R15.

<Rn>, LSL #shift

- значение, полученное LSL сдвигом хранимого в Rn числа на #shift разрядов.

<Rn>, LSL <Rm>

- значение, полученное LSL сдвигом хранимого в Rn числа на число разрядов указанных в Rm.

<Rn>, LSR #shift

- значение, полученное LSR сдвигом хранимого в Rn числа на #shift разрядов.

<Rn>, LSR <Rm>

- значение, полученное LSR сдвигом хранимого в Rn числа на число разрядов указанных в Rm.

<Rn>, ASR #shift

- значение, полученное ASR сдвигом хранимого в Rn числа на #shift разрядов.

<Rn>,ASR <Rm>

- значение, полученное ASR сдвигом хранимого в Rn числа на число разрядов указанных в Rm.

<Rn>, ROR #shift

- значение, полученное ROR сдвигом хранимого в Rn числа на #shift разрядов.

<Rn>, ROR <Rm>

- значение, полученное ROR сдвигом хранимого в Rn числа на число разрядов указанных в Rm.

<Rn>, RRX

- сдвиг на 1 разряд по правилам RRX.


 

Примеры команд, использующих <shifter_operand>:


 

mov r2, #0x0 ; #0

mov r2, r3 ; r3

mov r2, r3,lsl #0x15 ; r3, lsl #0x15

mov r2, r3,lsl r4 ; r3, lsl r4

mov r2, r3,lsr #0xC ; r3, lsr #0xC

mov r2, r3,lsr r4 ; r3, lsr r4

mov r2, r3,asr #0 ; r3, asr #0

mov r2, r3,asr r4 ; r3, asr r4

mov r2, r3,ror #0x12 ; r3, ror #0x12

mov r2, r3,ror r4 ; r3, ror r4

mov r2, r3,rrx ; r3, rrx 


 

 



 

Режимы адресации <addressing_mode>

Адресация для загрузки и сохранения слова или байта без знака <addressing_mode 1>

команды LDR STR LDRB STRB LDRT STRT LDRBT STRBT


 

Команды LDR и STR загрузки или сохранения word/byte формируются по следующей схеме:


 

LDR | STR {<cond>}{B}{T} <Rd>, <addressing_mode 1>


 

Где:


 

<cond> - модификаторы проверки условий, описаны выше. 

{B} - модификатор загрузки байта. При его наличии младшие 8 разрядов регистра загружается значения адресуемого байта памяти. Старшие 24 разряда заполняются нулями. При записи в память модифицируется значение только адресуемого байта. 


 

{T} - модификатор доступа к памяти в непривилегированном режиме (User mode). Если такого модификатора нет, доступ идет с привилегиями текущего режима процессора. Для команд с таким модификатором допустимы только режимы с постиндексацией (последние три режима адресации).


 

<addressing_mode 1>

[<Rn>]

-Адрес операнда хранится в регистре.

ldr r3, [r2]; в r3 загрузить слово хранимое по адресу r2 


 

[<Rn>, # -/+<offset_12>]

- адрес операнда вычисляется сложением или вычитанием значения в базовом регистре Rn и 12 разрядного непосредственного смещения. Знак хранится в отдельном бите ‘U’ кода команды, поэтому смещение занимает полные 12 разрядов 

(0 ... 0xFFF ).

str r3, [r2, # -0xFE8] ; r3 сохранить по адресу (r2-0xFE8)


 

[<Rn>, # -/+<offset_12>]!

- Прединдексация. Операция совпадает с предыдущей, но добавленный в конце восклицательный знак означает, что вычисленное значение адреса заносится в Rn.

ldr r3, [r2, # 0x30]! ] ; r3 сохранить по адресу (r2+0x30), r2 := (r2+0x30)


 

[<Rn>, +/- <Rm>]

- адрес операнда хранится в регистре Rn, смещение в Rm. Адрес операнда получается сложением или вычитанием Rn и Rm.

str r1,[r2,- r0]


 

[<Rn>, +/- <Rm>]!

- Прединдексация. Операция совпадает с предыдущей, но восклицательный знак, добавленный в конце, заставляет изменять Rn, туда заносится вычисленное значение адреса.

ldr r4,[r5, r7]!


 


 

[<Rn>, +/- <Rm>, <shift> #<shift_imm>]

- адрес операнда хранится в регистре Rn, смещение в Rm, величина сдвига для Rm в shift_imm, тип сдвига в shift . Адрес операнда вычисляется так:

addr := Rn +/- (Rm SHIFT shift_imm), то есть к Rm предварительно применяется операция сдвига.

Тип сдвигов <shift> - один из следующего ряда LSL LSR ASR ROR RRX, они были описаны ранее.

Допустимые величины сдвигов 1..32 для всех типов, кроме LSL , для LSL - 0..31. Для RRX величина сдвига не указывается, она всегда равна 1.

ldr r3,[r2, -r3, lsr #5]


 

[<Rn>, +/- <Rm>, <shift> #<shift_imm>]!

- Прединдексация. Операция совпадает с предыдущей, но восклицательный знак, добавленный в конце, заставляет изменять Rn, туда заносится вычисленное значение адреса.

ldr r0,[r2, -r3, lsl #7]!

[<Rn>], # -/+<offset_12>

- Постиндексация. В качестве адреса доступа к памяти берется значение Rn, после чего Rn изменяется, туда заносится значение полученное сложением или вычитанием Rn и 12 разрядного непосредственного смещения

str r5,[r3], #44

[<Rn>], +/- <Rm>

- Постиндексация. В качестве адреса доступа к памяти берется значение Rn, после чего Rn изменяется, туда заносится значение полученное сложением или вычитанием Rn и Rm.

ldr r1,[r7], -r2

[<Rn>], +/- <Rm>, <shift> #<shift_imm>

- Постиндексация. Адрес операнда хранится в регистре Rn, смещение в Rm, величина сдвига Rm в shift_imm, тип сдвига в shift . В качестве адреса доступа к памяти берется значение Rn, после чего Rn изменяется. Новый базовый адрес Rn вычисляется так:

addr := Rn +/- (Rm SHIFT shift_imm), то есть к Rm предварительно применяется операция сдвига.

Тип сдвигов <shift> - один из следующего ряда LSL LSR ASR ROR RRX, они были описаны ранее.

Допустимые величины сдвигов 1..32 для всех типов, кроме LSL , для LSL - 0..31. Для RRX величина сдвига не указывается, она всегда равна 1.

ldr r3,[r2], r5, ror #22


 



 

Адресация для дополнительных команд загрузки и сохранения <addressing_mode 2>

команды LDRD STRD LDRH STRH LDRSH LDRSB

[<Rn>]

-Адрес операнда хранится в регистре.

ldrh r3, [r2]; в r3 загрузить слово хранимое по адресу r2 

[<Rn>, # -/+<offset_8>]

- адрес операнда вычисляется сложением или вычитанием значения в базовом регистре Rn и 8 разрядного непосредственного смещения. Знак хранится в отдельном бите U кода команды, поэтому смещение занимает полные 8 разрядов (0 ... 0xFF ).

strh r3, [r2, # -0xE8] ; r3 сохранить по адресу (r2-0xe8)

[<Rn>, # -/+<offset_8>]!

- Прединдексация. Операция совпадает с предыдущей, но восклицательный знак, добавленный в конце, заставляет, заносить вычисленное значение адреса в Rn.

strd r3, [r2, # 0x30]! ;

[<Rn>, +/- <Rm>]

- адрес операнда хранится в регистре Rn, смещение в Rm. Адрес операнда получается сложением или вычитанием Rn и Rm.

ldrsb r1,[r2,- r0];

[<Rn>, +/- <Rm>]!

- Прединдексация. Операция совпадает с предыдущей, но восклицательный знак, добавленный в конце, заставляет изменять Rn, туда заносится вычисленное значение адреса.

ldrd r4,[r5, r7]!

[<Rn>], # -/+<offset_8>

- Постиндексация. В качестве адреса доступа к памяти берется значение Rn, после чего Rn изменяется , туда заносится значение полученное сложением или вычитанием Rn и 8 разрядного непосредственного смещения

strh r5,[r3], #44

[<Rn>], +/- <Rm>

- Постиндексация. В качестве адреса доступа к памяти берется значение Rn, после чего Rn изменяется , туда заносится значение полученное сложением или вычитанием Rn и Rm.

ldrsh r1,[r7], -r2


 

 


 



 

Адресация для мультирегисторной загрузки и сохранения <addressing_mode 3>

Команды STM LDM


 

Команда STM сохраняет любое число регистров общего назначения в памяти (возможно, все), а команда LDM загружает их. Режимы адресации таких команд генерируют последовательные адреса. Регистры с наименьшим номером сохраняются по младшим адресам, а регистры с наибольшими номерами, соответственно, по старшим. В коде команды младшие шестнадцать разрядов соответствуют шестнадцати регистрам общего назначения. Бит[0] соответствует R0, бит[15] регистру R15. Если какой-либо бит установлен в единицу, соответствующий регистр участвует в операции. 


 

LDM | STM {<cond>} <addressing_mode> <Rn>{!}, <registers> {^}


 

<cond> условия выполнения


 

<addressing_mode> одно из IB, FA, IA, EA, DB, FD, DA, ED - способ адресации


 

<Rn> регистр, в котором находится базовый адрес (базовый регистр)


 

{!} Признак постфиксной модификации базового регистра. Если присутствует, то значение Rn в конце операции увеличивается или уменьшается на величину (количество_регистров_в_операции * 4). 


 

<registers> Список регистров, задается в виде помещенного между '{' и '}' разделенного запятыми или дефисом списка регистров в порядке возрастания. Форма SP LR PC для специальных регистров также допускается. 


 

Пример: {R1-R5, R7, R9-R11, SP,LR,PC}; список из регистров с номерами 1,2,3,4,5,7,9,10,11,13,14,15


 

{^} Если в списке регистров загружаемых командой LDM нет регистра PC, этот модификатор указывает, что надо восстанавливать регистры банка пользовательского режима (текущий режим процессора может быть другим, со своим банком регистров). 

Если в списке регистров команды LDM есть регистр PC, то этот модификатор означает восстановление в конце операции регистра CPSR из SPSR текущего банка. 

Для команды STM этот модификатор означает, что сохранять надо регистры пользовательского режима.


 

Типы < addressing_mode 3>:

IA

(increment after). В качестве первого адреса берется значение из базового регистра Rn. Последующие адреса получаются увеличением предыдущего на четыре. Таким образом формируются адреса для всех загружаемых или сохраняемых регистров. 

IB

(increment before). В качестве первого адреса берется значение Rn+4. Последующие адреса получаются увеличением предыдущего на четыре. 

DA

(decrement after). В качестве первого адреса берется значение из базового регистра Rn. Последующие адреса получаются уменьшением предыдущего на четыре. 

DB

(decrement before). В качестве первого адреса берется значение Rn-4. Последующие адреса получаются уменьшением предыдущего на четыре. 

Стек. Адресация FA FD EA ED


 

Если в качестве базового операнда используется регистр R13, используемый как указатель стека SP, то признаки <addressing_mode 3> для удобства понимания могут быть заменены синонимами FA FD EA ED , указывающими тип стека. 


 

По какому принципу они выбираются. 

Если считается, что стек растет вниз, то есть при сохранении в стек указатель стека автоматически уменьшается, а при извлечении из него – увеличивается, тогда такой стек обозначают как Descending, модификатор D

Если полагают, что адресуемая указателем стека ячейка памяти занята и перед началом операции сохранения требуется сдвинуть указатель, такое поведение описывается модификатором F - Full. При считывании из F стека, соответственно предварительного сдвига не требуется, сначала необходимо взять значение, только затем изменить указатель.


 

Иное поведение стека описывается следующими модификаторами:

E - Empty. Ячейка памяти при сохранении считается пустой, сдвиг не нужен. Перед чтением необходим сдвиг.

A - Ascending. Применяется для стека, растущего вверх, который увеличивается при сохранении.


 

Из вышесказанного следует, что:

При сохранении:

FD = DB

ED = DA

EA = IA

FA = IB


 

При извлечении из стека:

FA = DA

FD = IA

EA = DB

ED = IB


 

В прошивке применяется FD тип стека.


 

Попробуем разобрать такую команду:


 

ldmeqib r0!,{r1,r3-r7,r9,r12,sp,lr};

LDM загрузить несколько регистров 

EQ команду выполнять, если Z=1

IB адреса, откуда загружать, увеличивать последовательно на 4(increment), включая адрес для первого регистра (before)

R0 базовый адрес находится в R0

! R0 в конце операции присвоить значение R0+(4*10)

{R1,R3,R4,R5,R6,R7,R9,R12,R13,R14} какие 10 регистров загружать


 

Адресация операций загрузки или сохранения регистров сопроцессора <addressing_mode C>

Команды LDC STC 


 

LDC{<cond>}{L} <coproc>,<CRd>,<addressing_mode C>


 

{L} - long load. 

<coproc> - имя сопроцессора (p0...p15)


 

<addressing_mode C> 

[<Rn>, #+/-<offset_8>*4]

Непосредственное смещение.

Этот режим адресации вызывает упорядоченную последовательность адресов. Первый адрес вычисляется прибавлением (или вычитанием) учетверенного значения смещения к значению регистра <Rn>. Последовательность следующих адресов формируется увеличением предыдущего на четыре. Это продолжается, пока сопроцессор не просигнализирует об окончании операции, что позволяет сопроцессору получить доступ к данным, размер которых определяется им. Сопроцессор не может требовать переноса более чем 16 слов. 

[<Rn>, #+/-<offset_8>*4]!

Непосредственное смещение с прединдексацией.

Этот режим адресации вызывает упорядоченную последовательность адресов. Первый адрес вычисляется прибавлением (или вычитанием) учетверенного значения смещения к значению регистра <Rn>. Если поле условия в команде соответствует коду состояния, то первый вычисленный адрес записывается в <Rn>. Последовательность следующих адресов формируется увеличением предыдущего на четыре. Это продолжается, пока сопроцессор не просигнализирует об окончании операции, что позволяет сопроцессору получить доступ к данным, размер которых определяется им. Сопроцессор не может требовать переноса более чем 16 слов. 


 



 

[<Rn>], #+/-<offset_8>*4

Непосредственное смещение с постиндексацией.

Этот режим адресации вызывает упорядоченную последовательность адресов. Первый адрес равен значению базового регистра [Rn]. Последовательность следующих адресов формируется увеличением предыдущего на четыре. Это продолжается, пока сопроцессор не просигнализирует об окончании операции, что позволяет сопроцессору получить доступ к данным, размер которых определяется им. Сопроцессор не может требовать переноса более чем 16 слов. 

Если поле условия в команде соответствует коду состояния, то новое значение <Rn> вычисляется прибавлением (или вычитанием) учетверенного значения смещения к значению регистра <Rn>.

[<Rn>], <option>

Адресация без индексирования.

Этот режим адресации вызывает упорядоченную последовательность адресов. Первый адрес равен значению базового регистра [Rn]. Последовательность следующих адресов формируется увеличением предыдущего на четыре Это продолжается, пока сопроцессор не просигнализирует об окончании операции, что позволяет сопроцессору получить доступ к данным, размер которых определяется им. Сопроцессор не может требовать переноса более чем 16 слов. 

Содержимое [Rn] не изменяется 

<option> - указывает дополнительные опции инструкции сопроцессора. Определяется синтаксисом инструкции как целое в диапазоне 0-255 окруженное { и }.


 



 

Команды ARM режима


 

Обозначения:

< > - в таких скобках указываются изменяемые части команды - модификаторы или операнды. 

<cond> - модификатор условия выполнения

S - модификатор установки флагов

<Rd> - регистр получатель результата

<Rn>,<Rm> - регистр, содержащий операнд. 

<Op2> – синоним <shifter_operand>

SP - R13 указатель стека

PC - R15 счетчик команд

LR - R14 регистр связывания


 

 

Фигурные скобки означают возможное присутствие необязательных модификаторов.

ADC 

ADC{<cond>}{S} <Rd>,<Rn>,<Op2> 

Rd := Rn + Op2 + C 

сумма с учетом переноса. 

S - разрешение установки флагов C Z N V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

ADD 

ADD{<cond>}{S} <Rd>,<Rn>,<Op2> 

Rd := Rn + Op2 

Сумма

S - разрешение установки флагов C Z N V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

AND 

AND{<cond>}{S} <Rd>,<Rn>,<Op2> 

Rd := Rn AND Op2 

побитная операция AND.

Нулевой (младший) разряд результата равен 1, если равны 1 младшие разряды в обоих операндах, иначе равен 0. Первый разряд результата равен 1, если равны 1 первые разряды в обоих операндах ... и.т.д. 

S - разрешение установки флагов Z N по результату операции. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

B{<cond>} <target_address> 

R15:= <target_address> 

Относительный переход по адресу <target_address> отстоящему от текущего максимум на 32 Mбайта вверх или вниз. Поле адреса в команде 24 разряда, значение умножается на 2, так и получается + - 32М адресов.

BL 

BL{<cond>} <target_address> 

R14:= R15 + 4; адрес следующей команды для возврата 

R15:= <target_address>;

Вызов подпрограммы по относительному адресу <target_address> отстоящему от текущего максимум на 32 Mбайта вверх или вниз. В R14 заносится адрес следующей за BL команды (адрес возврата).



 

BIC

BIC{<cond>}{S} <Rd>,<Rn>,<Op2>

Rd := Rn AND (NOT Op2) 

Очистка бит. 

Обнуление бит в тех позициях, в которых присутствует 1 в Op2 .

S - разрешение установки флагов Z N по результату операции. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

BKPT 

BKPT <16bitDebugInfo>

Вызов отладочного прерывания.

в отладчик передается любое 16 битное число указанное в качестве операнда, как информация о месте прерывания. Тип вызываемого исключения - Prefeth Abort

BLX

BLX <target_address> R14:= R15 + 4; адрес следующей команды для возврата 

R15:= <target_address>;

Вызов подпрограммы с возможной сменой набора команд.

Первая форма. Вызов подпрограммы по относительному адресу <target_address> на, примерно 32 мегабайта вверх или вниз. В R14 заносится адрес возврата. Используется для вызова подпрограммы Thumb, если младший бит адреса равен 1. 

BLX 

BLX{<cond>} <Rm> 

R14:= R15 + 4; адрес следующей команды для возврата 

R15:= Rm;

Вызов подпрограммы с возможной сменой набора команд.

Вторая форма. Вызов подпрограммы по абсолютному адресу Rm. В R14 заносится адрес возврата. Используется для вызова подпрограммы Thumb режима при 1 в младшем бите адреса. 

BX 

BX{<cond>} <Rm> 

R15:= Rm

Переход по абсолютному адресу Rm с возможной сменой набора команд.

Используется для перехода на коды Thumb режима при 1 в младшем бите адреса. 

CDP

CDP{<cond>} <coproc>, <opcode_1>,<CRd>,<CRn>,<CRm>,<opcode_2>

Выполнение инструкции сопроцессора

<coproc> - имя сопроцессора (p0...p15)

<opcode_1> - указывает какую инструкцию исполнять сопроцессору

<CRd> - регистр сопроцессора, получатель результата

<CRn> - регистр сопроцессора, первый операнд

<CRm> - регистр сопроцессора, второй операнд

<opcode_2>- указывает какую инструкцию исполнять сопроцессору (второе поле)

CDP (форма 2)

CDP <coproc>, <opcode_1>,<CRd>,<CRn>,<CRm>,<opcode_2>

Выполнение инструкции сопроцессора

<coproc> - имя сопроцессора (p0...p15)

<opcode_1> - указывает какую инструкцию исполнять сопроцессору

<CRd> - регистр сопроцессора, получатель результата

<CRn> - регистр сопроцессора, первый операнд

<CRm> - регистр сопроцессора, второй операнд

<opcode_2>- указывает какую инструкцию исполнять сопроцессору (второе поле)

В этой форме под коды инструкций выделяются дополнительные разряды.



 

CLZ

CLZ{<cond>} <Rd>,<Rn> (только ARM9E)

В Rd возвращается число ведущих двоичных нулей числа в Rn.

Пример: Если в Rn число 0x00800000, в Rd вернется 8.

CMN 

CMN{<cond>} <Rn>, <Op2> 

Сравнение со сменой знака. 

Флаги N Z C V устанавливаются в результате операции Rn + Op2, результат операции нигде не сохраняется. К примеру, 0xFFFFFFFF + 1 = 0, с переполнением, будут установлены в 1 флаги Z и C.

CMP 

CMP{<cond>} <Rn>, <Op2> 

Сравнение. 

Флаги N Z C V устанавливаются в результате операции Rn - Op2, результат операции нигде не сохраняется. 

EOR 

EOR{<cond>}{S} <Rd>,<Rn>,<Op2> 

Rd := Rn XOR Op2 

Исключающее ИЛИ. 

Единица будет установлена в тех двоичных разрядах Rd, в которых у операндов несовпадающее значение. Операция более известна под именем XOR. 

S - разрешение установки флагов Z N по результату операции. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

LDC

LDC{<cond>}{L} <coproc>, <CRd>,<addressing_mode C>

Загрузка нескольких регистров сопроцессора из памяти.

{L} - long load. Удвоение точности данных

<coproc> - имя сопроцессора (p0...p15)

<CRd> - первый из загружаемых регистров сопроцессора

<addressing_mode> - метод вычисления адреса

Количество регистров определяется сопроцессором, но не более 16.

LDC2

LDC2{L} <coproc>, <CRd>,<addressing_mode C>

Загрузка нескольких регистров сопроцессора из памяти.

{L} - long load. 

<coproc> - имя сопроцессора (p0...p15)

<CRd> - первый из загружаемых регистров сопроцессора

<addressing_mode> - метод вычисления адреса

Количество регистров определяется сопроцессором, но не более 16. Отличается отсутствием условия исполнения, что дает дополнительное место для опкодов сопроцессора.

LDM

LDM{<cond>}<addressing_mode 3> <Rn>{!}, <registers> {^}

Загрузка нескольких регистров из памяти.

См. addressing_mode 3

LDR

LDR{<cond>} <Rd>, <addressing_mode 1>

Rd := [address][31:0]

Загрузка 32 битного значения в регистр Rd из памяти.

<addressing_mode 1> - вычисляемый адрес



 

LDRB

LDRB{<cond>} <Rd>, <addressing_mode 1>

Rd[31:8] := 0x000000

Rd[7:0] := [address][7:0]

Загрузка байта из памяти с дополнением нулями в регистр Rd.

<addressing_mode> - вычисляемый адрес

LDRH

LDRH{<cond>} <Rd>, <addressing_mode 2>

Rd[31:16] := 0x0000

Rd[15:0] := [address][15:0]

Загрузка полуслова из памяти с дополнением нулями в регистр Rd 

<addressing_mode> - вычисляемый адрес

LDRSB

LDRSB{<cond>} <Rd>, <addressing_mode 2>

Rd[31:8] := 0xSSSSSS ; if ([address][7]== 1) S := F; else S: = 0;

Rd[7:0] := [address][7:0]

Загрузка байта с расширением знака в регистр Rd из памяти

<addressing_mode> - вычисляемый адрес

Если загружаемое число отрицательное (старший разряд =1) Rd[31:8] :=0xFFFFFF

Если загружаемое число положительно (старший разряд =0) Rd[31:8] :=0x000000

LDRSH

LDRSH{<cond>} <Rd>, <addressing_mode 2>

Rd[31:16] := 0xSSSS ; if ([address][15]== 1) S := F; else S: = 0;

Rd[15:0] := [address][15:0]

Загрузка полуслова с расширением знака в регистр Rd из памяти.

Если загружаемое число отрицательно (старший разряд =1) Rd[31:16] :=0xFFFF

Если загружаемое число положительно (старший разряд =0) Rd[31:16] :=0x0000

<addressing_mode 2> - вычисляемый адрес

LDRD

LDRD{<cond>} <Rd>, <addressing_mode 2>

Rd := [address][31:0] 

Rd+1 := [address+4][31:0] 

Загрузка пары регистров. 

Rd должен быть четным (R0 R2 R4 R6 R8 R10 R12)

<addressing_mode 2> - вычисляемый адрес

MCR

MCR{<cond>} <coproc>, <opcode1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}

Выполнение копирования данных из процессора в сопроцессор

<coproc> - имя сопроцессора (p0...p15)

<opcode_1> - указывает какую инструкцию исполнять сопроцессору

<Rd> - регистр (R0-R14) процессора, источник данных 

<CRn> - регистр получатель сопроцессора

<CRm> - дополнительный регистр сопроцессора, получатель либо источник данных

<opcode_2>- указывает какую инструкцию исполнять сопроцессору (второе поле). Если в команде не указано, считается равным 0.

CRn := rRn {<op>cRm}



 

MCR2

MCR2 <coproc>, <opcode1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}

Выполнение копирования данных из процессора в сопроцессор. Вторая форма с большей разрядностью команд сопроцессора.

<coproc> - имя сопроцессора (p0...p15)

<opcode_1> - указывает какую инструкцию исполнять сопроцессору

<Rd> - регистр (R0-R14) процессора, источник данных 

<CRn> - регистр получатель сопроцессора

<CRm> - дополнительный регистр сопроцессора, получатель либо источник данных

<opcode_2>- указывает какую инструкцию исполнять сопроцессору (второе поле). Если в команде не указано, считается равным 0.

CRn := rRn {<op>cRm}

MCRR

MCRR{<cond>} <coproc>, <opcode>, <Rd>, <Rn>, <CRm>

Выполнение копирования данных из двух регистров процессора в сопроцессор. 

<coproc> - имя сопроцессора (p0...p15)

<opcode_1> - указывает какую инструкцию исполнять сопроцессору

<Rd> - регистр (R0-R14) процессора, первый источник данных 

<Rn> - регистр (R0-R14) процессора, второй источник данных 

<CRm> - регистр сопроцессора, получатель данных


 

MLA

MLA{<cond>}{S} <Rd>,<Rm>,<Rs> ,<Rn>

Rd := (Rm * Rs) + Rn 

Умножение с накоплением со знаком либо без знака. Результат 32 разрядный. 

S - разрешение установки флагов Z N по результату операции.

MOV

MOV{<cond>}{S} <Rn>, <Op2>

Rd := Op2

Копирование значения в регистр

S - разрешение установки флагов Z N соответствует переносимому значению. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

MRC

MCR{<cond>} <coproc>, <opcode1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}

Rd:=cRn {<op>cRm}

Выполнение копирования данных из процессора в сопроцессор

<coproc> - имя сопроцессора (p0...p15)

<opcode_1> - указывает какую инструкцию исполнять сопроцессору

<Rd> - регистр процессора, получатель данных 

<CRn> - регистр сопроцессора содержащий первый операнд

<CRm> - дополнительный регистр сопроцессора, получатель либо источник данных

<opcode_2>- указывает какую инструкцию исполнять сопроцессору (второе поле). Если в команде не указано, считается равным 0.

MRC2

MCR2 <coproc>, <opcode1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}

См. MRC

Форма команды MRC без возможности проверки условия выполнения, с большей разрядностью опкодов сопроцессора.



 

MRRC

MRRC{<cond>} <coproc>, <opcode>, <Rd>, <Rn>, <CRm>

Выполнение копирования данных в два регистра процессора из сопроцессора. 

<coproc> - имя сопроцессора (p0...p15)

<opcode_1> - указывает какую инструкцию исполнять сопроцессору

<Rd> - регистр (R0-R14) процессора, первый получатель данных 

<Rn> - регистр (R0-R14) процессора, второй получатель данных 

<CRm> - регистр сопроцессора, источник данных

MRS

MRS{<cond>} <Rd>, CPSR

MRS{<cond>} <Rd>, SPSR

Rn := xPSR 

Копирование регистра статуса в регистр общего назначения

MSR

MSR{<cond>} CPSR_<fields>, <Rd> 

MSR{<cond>} SPSR_<fields>, #immediate

MSR{<cond>} CPSR_<fields>, <Rd> 

MSR{<cond>} SPSR_<fields>, #immediate


 

<fields> - одно или больше из последовательности 

c разрешить изменять PSR[7:0]

x разрешить изменять PSR[15:8]

s разрешить изменять PSR[23:16]

f разрешить изменять PSR[31:24]

Эти модификаторы устанавливают в единицу биты [19:16] в коде команды, которые используются как признаки разрешения обновления соответствующих полей в регистре состояния.

Инструкция предназначена для изменения значения флагов, битов разрешения прерываний, или процессорного режима в слове состояния. Из пользовательского режима (USER mode) в привилегированные переключиться не получится, так как операция работает только в привилегированных режимах.


 

Пример смены режима процессора:

MRS R0, CPSR ; Прочитать слово состояния

BIC R0, R0, #0x1F ; Очистить поле режима процессора

ORR R0, R0, #0x13 ; Установить в Supervisor

MSR CPSR_c, R0 ; Переключится в режим Supervisor

MUL

MUL{<cond>}{S} <Rd>,<Rm>,<Rs> 

Rd := Rm * Rs; 

Умножение операндов со знаком или без знака.

S - разрешение установки флагов Z N по результату операции.

MVN

MVN{<cond>}{S} <Rd>,<Op2>

Rd := NOT Op2

Перенести в <Rd> инвертированное значение <Op2>

S - разрешение установки флагов Z N соответствует переносимому значению. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!


 

NOP

Нет действия



 

ORR

ORR{<cond>}{S} <Rd>,<Rn>,<Op2> 

Rd := Rn OR Op2 ; 

Побитная операция ИЛИ.

Нулевой (младший) разряд результата равен 0, если равны 0 младшие разряды в обоих операндах, иначе равен 1. Первый разряд результата равен 0, если равны 0 первые разряды в обоих операндах ... и.т.д. 

S - разрешение установки флагов Z N по результату операции. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

PLD

PLD <addressing_mode >

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

RSB 

RSB{<cond>}{S} <Rd>,<Rn>,<Op2>

Rd := Op2 - Rn; Reverse Subtract 

Перевернутое вычитание.

Вычитание из второго операнда первого. S - разрешение установки флагов Z N C V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

RSC

RSC{<cond>}{S} <Rd>,<Rn>,<Op2>

Rd := Op2 - Rn – 1 + Carry; Reverse Subtract with Carry

Перевернутое вычитание с учетом переноса.

Вычитание из второго операнда первого. Если C==0, результат уменьшить на 1.

S - разрешение установки флагов Z N C V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

SBC

SBC{<cond>}{S} <Rd>,<Rn>,<Op2>

Rd := Rn - Op2 – 1 + Carry; Subtract with Carry 

Вычитание с учетом переноса.

Вычитание из первого операнда второго. Если C==0, результат уменьшить на 1.

S - разрешение установки флагов Z N C V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

STC

STC{<cond>}{L} <coproc>, <CRd>,<addressing_mode C>

{L} - long load. 

<coproc> - имя сопроцессора (p0...p15)

<CRd> - первый из сохраняемых регистров сопроцессора

См. <addressing_mode C> - метод вычисления адреса

Сохранение нескольких регистров сопроцессора в памяти. Количество регистров определяется сопроцессором, но не более 16.

STC2

STC2{L} <coproc>, <CRd>,<addressing_mode C>

{L} - long load. 

<coproc> - имя сопроцессора (p0...p15)

<CRd> - первый из сохраняемых регистров сопроцессора

См. <addressing_mode C> - метод вычисления адреса

Сохранение нескольких регистров сопроцессора в память. Количество регистров определяется сопроцессором, но не более 16. Отличается отсутствием условия исполнения, что дает дополнительное место для опкодов сопроцессора.

STM

STM{<cond>}<addressing_mode 3> <Rn>{!}, <registers> {^}

Сохранение нескольких регистров в память. 

См. addressing_mode 3

STR

STR{<cond>} <Rd>, <addressing_mode 1>

[address] [7:0] := Rd [7:0] 

[address+1][7:0] := Rd [15:8]

[address+2][7:0] := Rd [23:16]

[address+3][7:0] := Rd [31:24]

Сохранение 32 битного значения из регистр Rd в память.

См. <addressing_mode 1> - вычисляемый адрес

STRB

STRB{<cond>} <Rd>, <addressing_mode 1>

address[7:0] := Rd[7:0] 

Сохранение байта из регистра Rd в память.

См. <addressing_mode 1> - вычисляемый адрес

STRH 

STRB{<cond>} <Rd>, <addressing_mode 2>

[address] [7:0] := Rd [7:0] 

[address+1][7:0] := Rd [15:8]

Сохранение полуслова из регистра Rd в память.

См. <addressing_mode 2> - вычисляемый адрес

STRD

STRD{<cond>} <Rd>,<addressing_mode 2>

[address] [7:0] := Rd [7:0] 

[address+1][7:0] := Rd [15:8]

[address+2][7:0] := Rd [23:16]

[address+3][7:0] := Rd [31:24]

[address+4][7:0] := Rd+1 [7:0] 

[address+5][7:0] := Rd+1 [15:8]

[address+6][7:0] := Rd+1 [23:16]

[address+7][7:0] := Rd+1 [31:24]

Сохранение 64 разрядного числа из регистров Rd и Rd+1 в память.

См. <addressing_mode 2> - вычисляемый адрес

SUB

SUB{<cond>}{S} <Rd>,<Rn>,<Op2>

Rd := Rn - Op2;

Вычитание.

S - разрешение установки флагов Z N C V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

SWI

SWI{<cond>} <24 бит значение>

Программное прерывание, вызов обслуживания ОS. 

Исключение с вектором 0x8, в LR заносится адрес следующей за SWI команды.

Передаваемое значение должно быть в пределах от 0 до 255, оно игнорируется процессором, но передается в операционную систему для определения требуемой операции OS


 


 

SWP 

SWP{<cond>} <Rd>,<Rm>,[<Rn>]

Rd := [Rn], [Rn] := Rm 

Обмен значением между памятью и регистром.

Содержимое ячейки с адресом Rn помещается в Rd

Содержимое Rm сохраняется в ячейке с адресом Rn. Операция служит 

SWPB

SWPB{<cond>} <Rd>,<Rm>,[<Rn>]

Rd := ZeroExtended[Rn][7:0] 

[Rn][7:0] := Rm

Обмен байта между памятью и байтом.

TEQ

TEQ{<cond>}{S} <Rn>,<Op2>

CPSR flags:= Rn EOR Op2 

Установка флагов в N Z результате операции EOR(XOR) между Rn и Op2. Результат операции нигде не сохраняется. 

Флаг C может быть установлен операцией сдвига Op2 (См. shifter_operand). 

TST

CPSR flags:= Rn AND Op2 

Установка флагов в N Z результате операции AND между Rn и Op2. Результат операции нигде не сохраняется. 

Флаг C может быть установлен операцией сдвига Op2 (См. shifter_operand). 



 

DSP - подобные операции

Арифметика с насыщением. QADD QDADD QSUB QDSUB 

Насыщение – случай превышения результатом операции максимального (или минимального для отрицательного числа) возможного, определяемого его разрядностью, значения. В отличие от случая переполнения, результат операции ограничивается максимальным (минимальным) значением. 

QADD

QADD{<cond>} <Rd>,<Rm>,<Rn>

Rd := SAT (Rm + Rn) Saturated add 

Сложение с насыщением. Оба операнда рассматриваются как 32 разрядные числа со знаком. Если в результате сложения двух положительных чисел результат превосходит величину 0x7FFFFFFF, то возвращается результат 0x7FFFFFFF и устанавливается в 1 флаг Q.

Если в результате сложения двух отрицательных чисел получаемый результат меньше величины 0x80000000 (минимального 32 разр. отрицательного числа), то возвращается результат 0x80000000 и устанавливается в 1 флаг Q.


 

Пример для ARMDebugger :

$ARM9E ; версия процессора

AREA STARTUPCODE, CODE

code32

start_:

ldr r0, =0x7FFFFFFE ;уже большое число 

ldr r1, =0xFF ;добавим чуть - чуть

qadd r2,r0,r1 ;вернет R2 = 0x7FFFFFFF, Q flag =1 

bx lr

END

QDADD

QDADD{<cond>} <Rd>,<Rm>,<Rn>

Rd := SAT (Rm + SAT (Rn * 2)) 

Прибавление удвоенного с насыщением.

Rn умножается на 2, результат умножения - с насыщением. Полученное произведение прибавляется к Rm, сумма – с насыщением. Q флаг устанавливается при любом насыщении.

QSUB

QSUB{<cond>} <Rd>,<Rm>,<Rn>

Rd := SAT (Rm - Rn) 

Вычитание с насыщением. Для подробностей см. QADD

QDSUB 

QDSUB{<cond>} <Rd>,<Rm>,<Rn>

Rd := SAT (Rm - SAT (Rn*2)); 

Вычитание удвоенного с насыщением. Q флаг устанавливается при любом насыщении.

См. QADD QDADD

Команды арифметики с учетом знака и установкой флага Q. SMULxy SMULWy …


 

В большинстве последующих команд регистры рассматриваются как два 16 разрядных значения (halfword) со знаком. Под x и y в мнемонике команды понимается указатель на старшее (top) или младшее (bottom) 16 разрядное полуслово. Комбинации для xy - BB BT TB TT, соответственно указывают, какие полуслова будут участвовать в операции. 

BB – из обоих регистров в операции участвуют младшие полуслова. 

BT – из первого регистра младшее из второго старшее, и т д... 

Если в мнемонике указан только y модификатор, он указывает, какое полуслово берется из второго операнда – регистра и, соответственно, может быть B или T.



 

SMULxy

SMULxy{<COND>} <Rd>,<Rm>,<Rs

Rd := Rm[x] * Rs[y]

Умножение двух 16 разрядных чисел со знаком, 32 разрядный результат в Rd.

Пример: 

smultb r0,r1,r2; R0 = R1[31:16] * R2[15:0] 

smulbb r0,r0,r0; Возведение R0[15:0] в квадрат

SMULWy

SMULWy{<COND>} <Rd>,<Rm>,<Rs> 

Rd := (Rm * Rs[y])[47:16] 

Умножение (32 x 16) разрядов

Умножение 32 разрядного числа со знаком Rm на 16 разрядное Rs[y] со знаком, 32 старших разряда из полученного 48 разрядного результата поместить в Rd

SMLAxy

SMLAxy{<COND>} <Rd>,<Rm>,<Rs>,<Rn> 

Rd := Rn + Rm[x] * Rs[y] 

умножение (16 x 16) разрядов с 32 разрядным накоплением

Умножение двух 16 разрядных чисел со знаком Rm[x] Rs[y], 32 разрядный результат прибавить к Rn с учетом знака, сумму поместить в Rd. Если при накоплении наступит насыщение, флаг Q будет установлен в 1, но результат не ограничивается.

SMLAWy

SMLAWy{<COND>} <Rd>,<Rm>,<Rs>,<Rn> 

Rd := Rn+(Rm * Rs[y])[47:16] 

Умножение (32 x 16) разрядов с 32 разрядным накоплением.

Умножение 32 разрядного числа со знаком Rm на 16 разрядное Rs[y] со знаком, 32 старших разряда из полученного 48 разрядного результата прибавить к Rn с учетом знака, сумму поместить в Rd. Если при накоплении наступит насыщение, флаг Q будет установлен в 1, но результат не ограничивается.

SMLALxy

SMLALxy{<COND>} <RHi>,<RLo>,<Rm>,<Rs

RdHi,RdLo := RdHi,RdLo + Rm[x]*Rs[y] 

умножение (16 x 16) разрядов с 64 разрядным накоплением.

В качестве 64 разрядного значения выступает пара регистров RdHi,RdLo.

Умножение двух 16 разрядных чисел со знаком Rm[x] Rs[y], 32 разрядный результат прибавить к RdHi,RdLo с учетом знака, сумму поместить в RdHi,RdLo


 


 



 

Набор команд Thumb.


 

Команды Thumb набора имеют гораздо меньше возможных форм и проще в изучении.


 

Некоторые пояснения:

< > - в таких скобках указываются изменяемые части команды - модификаторы или операнды. 

Операнды могут быть:

#<imm_X> - X битное непосредственное значение, хранится в коде программы

<Rx> - регистр, в команде хранится его номер.

Модификаторы:

<cond> - поле условного выполнения. Совпадает с ARM набором. 


 

Команды описаны в “развернутом” виде, приближенном к тому, как они хранятся в памяти программ и исполняются ядром процессора. Что это дает? К примеру, команда перехода B:


 

B(1)

B<cond> <signed imm_8>

PC := (signed imm_8 * 2) + PC + 4;

Условный относительный переход на, приблизительно, +/-255 байт, только на четные адреса. 

<cond> - поле условий, полностью совпадает с режимом ARM

beq address;


 

Что можно увидеть в таком описании? Во первых, команда имеет модификатор 

условия <cond>. Во вторых, смещение хранится в виде восьмиразрядного значения со знаком. В третьих, перед прибавлением к PC это значение умножается на 2, соответственно адрес перехода может быть только четным и отстоять от текущего не более чем на ~127*2 = 255 байт (127 – потому что один бит уходит на знак). Ну и в четвертых, видно, что максимальное положительное смещение больше, чем максимальное отрицательное из-за известного свойства чтения регистра R15 (в режиме Thumb считываемое из него значение равно текущему адресу + 4).

ADC

ADC <Rd>,<Rm>

Rd := Rd + Rm + C

Сложение с переносом

Применимы только регистры R0-R7

Изменяемые флаги: N, Z, C, V

adc r0,r1;

ADD(1)

ADD <Rd>,<Rm>,#<imm_3>

Rd := Rm + #imm_3

Прибавление к Rm трехразрядного значения. Результат в Rd

Применимы только регистры R0-R7

Изменяемые флаги: N, Z, C, V

Примечание: несмотря на то, что второе слагаемое для этой команды - только положительное число не большее, чем 7 (111b), можно указывать и отрицательное, тогда в программу будет вставлена команда sub Rd,Rm,#imm_3. Это относится ко многим командам add, имеющим sub “пары”.

add r0,r1,#7;

add r0,r1,#-7; пара sub r0,r1,#7

ADD(2)

ADD <Rd>,#<imm_8>

Rd := Rd + #<imm_8>

Сумма Rd и imm_8, результат поместить в Rd

Применимы только регистры R0-R7

Изменяемые флаги: N, Z, C, V

add r0,#255 ;

add r0,#-255 ; sub пара



 

ADD(3)

ADD <Rd>,<Rn>,<Rm>

Rd := Rn + Rm

Сумма Rn и Rm, результат поместить в Rd

Применимы только регистры R0-R7

Изменяемые флаги: N, Z, C, V

add r0,r1,r2;

ADD(4)

ADD <Rd>,<Rm>

Rd := Rd + Rm

Применимы регистры R0-R15. Но применение одновременно двух младших регистров недопустимо, результат непредсказуем.

флаги не изменяются

add r0,r1;

ADD(5)

ADD <Rd>,PC,<#imm_8> * 4

Rd := (PC AND 0xFFFFFFFC)+ #immed_8 << 2

Применимы регистры R0-R7. Только значение кратное 4 и меньшее, чем 1020 можно указывать в качестве слагаемого. 

флаги не изменяются

add r0,pc,#4; -допустимо 

add r0,pc,#5; -недопустимо, не кратно 4

add r0,pc,#1020; 255 * 4 =1020 максимально допустимое смещение

add r0,pc,#1024; недопустимо, больше 1020

add r0,pc,#-24; недопустимо, пары sub нет

ADD(6)

ADD <Rd>,SP,#<imm_8> * 4

Rd := SP + #immed_8 << 2

Применимы регистры R0-R7. Только значение кратное 4 и меньшее, чем 1020 можно указывать в качестве смещения. Максимальное слагаемое равно (2**8-1)*4 = 1020.

флаги не изменяются

add r0,sp,#20; 

add r0,sp,#-4; недопустимо, пары sub нет

ADD(7)

ADD SP,#<imm_7> * 4

SP := SP + #imm_7 << 2

Только значение кратное 4 и меньшее, чем 508 можно указывать в качестве слагаемого.

флаги не изменяются

add sp,#16;

add sp,#-16; sub пара

AND

AND <Rd>,<Rm>

Rd := Rd AND Rm

Логическое И

Применимы регистры R0-R7. 

Изменяемые флаги: N, Z

and r0,r1;



 

ASR(1)

ASR <Rd>,<Rm>,#<imm_5>

Rd := (signed) Rm >> imm_5

Арифметический сдвиг вправо со знаком (деление на степень 2). В отличии от логического сдвига, при арифметическом происходит расширение знакового разряда (т. е. во все старшие разряды, “освобожденные” при сдвиге заносится 1 для отрицательного или 0 для положительного числа). Применимы регистры R0-R7. 

Изменяемые флаги: N, Z, последний выдвинутый в результате сдвига разряд помещается в C.

Если указать сдвиг на 0, это трактуется как сдвиг на 32! 

asr r0,r1,#31;

ASR(2)

ASR <Rd>,<Rs>

Rd := (signed) Rm >> Rs

Арифметический сдвиг вправо со знаком (деление на степень двойки). В отличие от логического сдвига, при арифметическом происходит расширение знакового разряда (т. е. во все старшие разряды, “освобожденные” при сдвиге заносится 1 для отрицательного или 0 для положительного числа). 

Применимы регистры R0-R7. 

Изменяемые флаги: N, Z, последний выдвинутый в результате сдвига разряд помещается в C.

asr r0,r1;

B(1)

B<cond> <signed imm_8>

R15 := (signed imm_8 * 2) + PC + 4;

Условный относительный переход на, приблизительно, +/-255 байт, только на четные адреса. 

<cond> - поле условий, полностью совпадает с режимом ARM

beq address;

B(2)

B <signed imm_12>

R15 := (signed imm_12 * 2) + PC + 4;

Безусловный относительный переход на, приблизительно, +/-2048 байт, только на четные адреса. 

b address;

BIC

BIC <Rd>,<Rm>

Rd := Rd AND NOT Rm

Очистка бит.

Сбрасывает в 0 биты в тех разрядах Rd, которые равны 1 в Rm

Применимы регистры R0-R7. 

Изменяемые флаги: N, Z

bic r0,r1;

BKPT

BKPT #<imm_8>

LR:= адрес возврата

PC:= 0x0C (или 0xFFFF000C)

Точка отладочного останова. 

Восьмиразрядное значение передается в отладчик для индикации места останова.

bkpt #123;


 



 

BL 

BL <address>

PC:= address

LR:= адрес следующей команды

Вызов подпрограммы по относительному адресу. Команда занимает в памяти 4 байта и состоит из двух 2х байтных частей, в первой из которых находится старшие 11 разрядов, а во второй младшие 11 разрядов смещения. Максимальное смещение адреса примерно равно +/- 0x3FFFFF (~ +/-4MB) 

bl address;

BLX(1) 

BLX <address>

PC:= address & 0xFFFFFFFC

LR:= адрес следующей команды

T = 0

Вызов подпрограммы по относительному адресу с обязательной сменой набора команд на ARM. Команда занимает в памяти 4 байта и состоит из двух 2х байтных частей, в первой из которых находится старшие 11 разрядов, а во второй младшие 11 разрядов смещения. Максимальное смещение адреса примерно равно +/- 0x3FFFFF (~ +/-4MB) 

blx address;

BLX(2) 

BLX <Rm>

PC:= Rm & 0xFFFFFFFE

LR:= адрес следующей команды

T = Rm[0]

Вызов подпрограммы по адресу в Rm с возможной сменой набора команд на ARM. Если младший бит адреса == 0, происходит смена набора команд, при этом недопустим переход на адрес не выравненный кратно четырем.

Применимы регистры R0-R14.

ldr r0,=address;

blx r0;

BX 

BX <Rm>

PC:= Rm & 0xFFFFFFFE

T = Rm[0]

Переход по адресу в Rm с возможной сменой набора команд на ARM. Если младший бит адреса == 0, происходит смена набора команд, при этом недопустим переход на адрес не выравненный кратно четырем.

Применимы регистры R0-R14.

ldr r0,=address;

bx r0;

CMN

CMN <Rn>,<Rm>

Установка флагов в соответствии с результатом сложения Rn + Rm. Результат не сохраняется.

Применимы только регистры R0-R7

Изменяемые флаги: N, Z, C, V

cmn r0,r1;

CMP(1)

CMP <Rn>, #imm_8

Установка флагов в соответствии с результатом операции Rnimm_8, результат не сохраняется. Максимальное значение второго операнда равно 255.

Применимы только регистры R0-R7

Изменяемые флаги: N, Z, C, V

cmp r0,#0xEB;

CMP(2)

CMP <Rn>, <Rm>

Установка флагов в соответствии с результатом операции Rn - Rm. Результат не сохраняется.

Применимы регистры R0-R15. В случае присутствия в качестве любого операнда старшего регистра, формируется команда с другим кодом. Это не имеет никакого значения при программировании, но иногда приходится учитывать при деассемблировании.

Изменяемые флаги: N, Z, C, V

cmp r0,r1;

cmp r12,r3; - другой код


 

EOR

EOR <Rd>,<Rm>

Rd := Rd EOR Rm

Исключающее ИЛИ.

Логическая операция, при которой каждый разряд результата устанавливается в 

Применимы регистры R0-R7. 

Изменяемые флаги: N, Z

eor r0,r1;

LDMIA

LDMIA <Rn>!, <registers>

Загрузка нескольких регистров по списку, регистры загружаются последовательно, начиная с самого маленького номера и заканчивая наибольшим, первый регистр загружается значением, хранящимся по адресу Rn, адрес загружаемого значения для каждого следующего регистра увеличивается на 4 (Load Multiple Increment After). 

<Rn> регистр, хранящий перед началом операции стартовый адрес. 

! – указывает, что по завершению операции значение <Rn> обновляется, увеличиваясь на величину равную учетверенному количеству загруженных регистров, это не опция, указывается для подсказки.

<registers> - список из нескольких (возможно, всех) младших регистров.

ldmia r0!,{r1,r3,r5-r7};

LDR(1)

LDR <Rd>, [<Rn>, #<imm_5> * 4]

Rd:=(Rn+imm_5*4)[31:0]

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции. Должен быть выравнен кратно 4 байтам, иначе загрузится непредсказуемое значение.

<imm_5> - пятибитное число, которое умножается на 4 и прибавляется к значению Rn для получения адреса загружаемого значения. 
Максимальное смещение равно (2**5 -1) * 4 = 124.

Применимы регистры R0-R7.

ldr r0,[r1,#120];

LDR(2)

LDR <Rd>, [<Rn>, <Rm>]

Rd:=(Rn+Rm)[31:0]

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции. 

<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса загружаемого значения. Полученный адрес должен быть выравнен кратно 4 байтам, иначе загрузится непредсказуемое значение.

Применимы регистры R0-R7.

ldr r0,[r1,r2];


 



 

LDR(3)

LDR <Rd>, [PC, #<imm_8> * 4]

Rd=((PC & 0xFFFFFFFC) + (imm_8*4))[31:0] 

<Rd> - регистр в которое загружается значение

PC – счетчик команд.

<imm_8> - восьмибитное число, которое умножается на 4 и прибавляется к значению PC для получения адреса загружаемого значения. Обратите внимание, что значение из PC берется с обнуленными двумя младшими битами. Максимальное смещение равно (2**8 -1) * 4 = 1020.

Применимы регистры R0-R7.

ldr r0,[r15,#120];

LDR(4)

LDR <Rd>, [SP, #<imm_8> * 4]

Rd:= (SP + imm_8 * 4)[31:0] 

<Rd> - регистр в которое загружается значение

SPR13 указатель стека.

<imm_8> - пятибитное число, которое умножается на 4 и прибавляется к значению SP для получения адреса загружаемого значения. Полученный адрес должен быть выравнен кратно 4 байтам, иначе загрузится непредсказуемое значение. Эта форма команды обычно используется для извлечения значения параметров функции, передаваемых через стек. Максимальное смещение равно (2**8 - 1) * 4 = 1020.

Применимы регистры R0-R7.

ldr r0,[sp,#12];

LDRB(1)

LDRB <Rd>, [<Rn>, #<imm_5>]

Rd[31:8]:=0x000000;

Rd[7:0]:=(Rn+imm_5)[7:0];

Загрузка в регистр байта с дополнением нулями из памяти 

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции.

<imm_5> - пятибитное число, которое прибавляется к значению Rn для получения адреса загружаемого значения. Максимальное смещение равно (2**5-1)= 31.

Применимы регистры R0-R7.

ldrb r0,[r1,#31]

LDRB(2)

LDRB <Rd>, [<Rn>, <Rm>]

Rd[31:8]:=0x000000;

Rd[7:0]:=(Rn+Rm)[7:0]

Загрузка в регистр байта с дополнением нулями из памяти 

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции. 

<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса загружаемого значения. 

Применимы регистры R0-R7.

ldrb r0,[r1,r2];

LDRH(1)

LDRH <Rd>, [<Rn>, #<imm_5> * 2]

Rd[31:16]:=0x0000;

Rd[15:0]:=(Rn+imm_5 * 2)[15:0];

Загрузка в регистр полуслова с дополнением нулями из памяти 

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции. Адрес должен быть выравнен кратно 2 байтам.

<imm_5> - пятибитное число, удвоенное значение которого прибавляется к Rn для получения адреса загрузки. Максимальное смещение равно (2**5 -1) *2 = 62. 

Применимы регистры R0-R7.

ldrh r0,[r1,#62];


 



 

LDRH(2)

LDRH <Rd>, [<Rn>, <Rm>]

Rd[31:16]:=0x0000;

Rd[15:0]:=(Rn+Rm)[15:0]

Загрузка в регистр полуслова с дополнением нулями из памяти 

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции. 

<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса загружаемого значения. Полученный адрес должен быть выравнен кратно 2 байтам, иначе загрузится непредсказуемое значение. 

Применимы регистры R0-R7.

ldrh r0,[r1,r2];

LDRSB

LDRB <Rd>, [<Rn>, <Rm>]

if ((Rn+Rm)[7] == 0) Rd[31:8]:=0x000000; 

else Rd[31:8]:=0xFFFFFF; 

Rd[7:0]:=(Rn+Rm)[7:0]

Загрузка в регистр байта с расширением знака из памяти 

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции. 

<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса загружаемого значения. 

Применимы регистры R0-R7.

ldrsb r0,[r1,r2];

LDRSH

LDRH <Rd>, [<Rn>, <Rm>]

if ((Rn+Rm)[15] == 0)

Rd[31:16]:=0x0000; 

else

Rd[31:16]:=0xFFFF; 

Rd[15:0]:=(Rn+Rm)[15:0];

Загрузка в регистр полуслова с расширением знака из памяти 

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции. 

<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса загружаемого значения. 

Применимы регистры R0-R7.

ldrsh r0,[r1,r2];

LSL(1)

LSL <Rd>, <Rm>, #imm_5

Rd := Rm << imm5;

Логический сдвиг влево значения из Rm, результат поместить в Rd.

Применимы регистры R0-R7.

Изменяемые флаги: C, N, Z

lsl r0,r1,#31;

LSL(2)

LSL <Rd>, <Rm>, <Rs>

Rd := Rm << Rs;

Логический сдвиг влево значения из Rm, результат поместить в Rd.

Применимы регистры R0-R7.

Изменяемые флаги: C, N, Z

lsl r1,r2,r3;


 



 

LSR(1)

LSR <Rd>, <Rm>, #imm_5

Rd := Rm >> imm5;

Логический сдвиг вправо значения из Rm, результат поместить в Rd.

Применимы регистры R0-R7.

Изменяемые флаги: C, N, Z

lsr r0,r1,#31; 

LSR(2)

LSR <Rd>, <Rm>, <Rs>

Rd := Rm >> Rs;

Логический сдвиг вправо значения из Rm, результат поместить в Rd.

Применимы регистры R0-R7.

Изменяемые флаги: C, N, Z

lsr r0,r1,r3; 

MOV(1)

MOV <Rd>,#<imm_8>

Занесение в Rd непосредственного 8 разрядного значения.

Применимы регистры R0-R7.

Изменяемые флаги: Z

mov r0,#255;

MOV(2)

MOV <Rd>,<Rn>

Rd := Rn

Занесение в Rd значения из Rn. Оба регистра должны быть младшими.

Применимы регистры R0-R7.

Изменяемые флаги: N,Z

mov r0,r1;

MOV(3)

MOV <Rd>,<Rn>

Rd := Rn

Занесение в Rd значения из Rn. В этой форме команды один или оба регистра должны быть старшими, код команды отличается от предыдущей, флаги не меняются.

Применимы регистры R0-R15.

Флагов не меняет.

mov r0,r8;

mov r15,r14; синоним RET 

MUL

MUL <Rd>,<Rm>

Rd := (Rm * Rs)[31:0]

Умножение двух регистров со знаком или без знака, младшие 32 бита результата помещаются в Rd.

Применимы регистры R0-R7.

Изменяемые флаги: N,Z

mul r0,r1;

MVN

MVN <Rd>,<Rm>

Rd := NOT Rm

Поместить в Rd инвертированное значение из Rm

Применимы регистры R0-R7.

Изменяемые флаги: N,Z

mvn r0,r1;


 



 

NEG

NEG <Rd>,<Rm>

Rd := -Rm

Поместить в Rd значение из Rm, предварительно сменив знак числа. 

Применимы регистры R0-R7. Изменяемые флаги: N,Z,C,V

neg r0,r1;

ORR

ORR <Rd>,<Rm>

Rd := Rd OR Rm

Логическое ИЛИ.

Применимы регистры R0-R7. Изменяемые флаги: N,Z

orr r0,r1;

POP

POP <registers>

Загрузка из стека нескольких (возможно, всех) младших регистров и, возможно, регистра PC. Регистры загружаются последовательно, начиная с самого младшего номера и заканчивая наибольшим номером. Начальный адрес для загрузки первого регистра равен значению SP. Адрес для загрузки каждого следующего регистра увеличивается на 4. В конце операции значение SP увеличивается на учетверенное число загруженных регистров.

<registers> - список регистров разделенных запятой или указанных через дефис, в фигурных скобках.

Применимы регистры R0-R7,PC.

pop {r0,r2,r3};

pop {r0,r2,r4-r6,PC};

PUSH

PUSH <registers>

Сохранение в стек нескольких (возможно, всех) младших регистров и, возможно, регистра LR.

Регистры сохраняются последовательно, начиная с самого большого номера и заканчивая самым маленьким номером. Начальный адрес для сохранения первого регистра равен значению SP. Адрес для сохранения каждого следующего регистра уменьшается на 4. В конце операции значение SP уменьшается на учетверенное число сохраненных регистров.

<registers> - список регистров разделенных запятой или указанных через дефис, в фигурных скобках.

Применимы регистры R0-R7,LR.

push {r0,r2,r3};

push {r0,r2,r4-r6,LR};

ROR

ROR <Rd>,<Rs>

Rd := Rd ROR Rs[7:0]

Команда правого циклического сдвига значения в Rd на число разрядов указанное в Rs. Биты выдвинутые из регистра справа помещаются в освободившиеся слева разряды. 

Применимы регистры R0-R7

Изменяемые флаги: N,Z по результату операции, C равно последнему выдвинутому справа разряду.

ror r0,r1;

SBC

SBC <Rd>,<Rm>

Rd := Rd - Rm - NOT C

Вычитание с учетом переноса.

Применимы регистры R0-R7. Изменяемые флаги: N,Z,C,V

sbc r0,r1;



 

STMIA

STMIA <Rn>!, <registers>

Сохранение нескольких регистров по списку.

Регистры сохраняются последовательно, начиная с самого маленького номера и заканчивая наибольшим. Первый регистр сохраняется в ячейку по адресу Rn, адрес сохранения для каждого следующего регистра увеличивается на 4 (Load Multiple Increment After). 

<Rn> регистр, хранящий перед началом операции стартовый адрес. 

! – указывает, что по завершению операции значение <Rn> обновляется, увеличиваясь на величину равную учетверенному количеству сохраненных регистров, это не опция, указывается для подсказки.

<registers> - список из нескольких (возможно, всех) младших регистров разделенных запятой или указанных через дефис, в фигурных скобках.

stmia r0!,{r1,r3,r5-r7};

STR(1)

STR <Rd>, [<Rn>, #<imm_5> * 4]

(Rn+imm_5*4)[31:0] := Rd

Сохранение значения из регистра в память.

<Rd> - регистр в значение которого сохраняется. 

<Rn> - базовый адрес для операции. Должен быть выравнен кратно 4 байтам.

<imm_5> - пятибитное число, которое умножается на 4 и прибавляется к значению Rn для получения адреса сохранения. 
Максимальное смещение равно (2**5 -1) * 4 = 124.

Применимы регистры R0-R7.

str r0,[r1,#120];

STR(2)

STR <Rd>, [<Rn>, <Rm>]

(Rn+Rm)[31:0]:= Rd

Сохранение значения из регистра в память.

<Rd> - регистр значение которого сохраняется. 

<Rn> - базовый адрес для операции. 

<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса сохранения. Полученный адрес должен быть выравнен кратно 4 байтам, иначе результат непредсказуем.

Применимы регистры R0-R7.

str r0,[r1,r2];

STR(3)

STR <Rd>, [SP, #<imm_8> * 4]

(SP + imm_8 * 4)[31:0] := Rd 

Сохранение значения из регистра в стек.

<Rd> - регистр значение которого сохраняется.

SPR13 указатель стека.

<imm_8> - восьмибитное число, которое умножается на 4 и прибавляется к значению SP для получения адреса сохранения регистра. Полученный адрес должен быть выравнен кратно 4 байтам. Максимальное смещение равно (2**8 - 1) * 4 = 1020.

Применимы регистры R0-R7.

str r0,[sp,#40];

STRB(1)

STRB <Rd>, [<Rn>, #<imm_5>]

(Rn+imm_5)[7:0] := Rd[7:0];

Сохранение байта из регистра в память 

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции.

<imm_5> - пятибитное число, которое прибавляется к значению Rn для получения адреса сохранения. Максимальное смещение равно (2**5-1)= 31.

Применимы регистры R0-R7.

strb r0,[r1,#31]

STRB(2)

STRB <Rd>, [<Rn>, <Rm>]

(Rn+Rm)[7:0] := Rd[7:0]

Сохранение байта из регистра в память

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции. 

<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса сохранения. 

Применимы регистры R0-R7.

strb r0,[r1,r2];

STRH(1)

STRH <Rd>, [<Rn>, #<imm_5> * 2]

(Rn+imm_5 * 2)[15:0] := Rd[15:0]

Сохранение полуслова из регистра в память

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции. Адрес должен быть выравнен кратно 2 байтам.

<imm_5> - пятибитное число, удвоенное значение которого прибавляется к Rn для получения адреса сохранения. Максимальное смещение равно (2**5 -1) *2 = 62. 

Применимы регистры R0-R7.

strh r0,[r1,#62];


 

STRH(2)

STRH <Rd>, [<Rn>, <Rm>]

(Rn+Rm)[15:0] := Rd[15:0]

Сохранение полуслова из регистра в память

<Rd> - регистр в которое загружается значение

<Rn> - базовый адрес для операции. 

<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса сохранения. Полученный адрес должен быть выравнен кратно 2 байтам. 

Применимы регистры R0-R7.

strh r0,[r1,r2];


 

SWI

Программное прерывание, вызов сервисов ОS. 

Исключение с вектором 0x8, в LR заносится адрес следующей за SWI команды.

Передаваемое значение должно быть в пределах от 0 до 255, оно игнорируется процессором, но передается в операционную систему для определения требуемой операции OS.


 


 

SUB(1)

SUB <Rd>,<Rm>,#<imm_3>

Rd := Rm - #imm_3

Вычитание из Rm трехразрядного значения. Результат в Rd

Применимы только регистры R0-R7

Изменяемые флаги: N, Z, C, V

sub r0,r1,#7;

SUB(2)

SUB <Rd>,#<imm_8>

Rd := Rd - #<imm_8>

Разность Rd и imm_8, результат поместить в Rd

Применимы только регистры R0-R7

Изменяемые флаги: N, Z, C, V

sub r0,#255 ;



 

SUB(3)

SUB <Rd>,<Rn>,<Rm>

Rd := Rn + Rm

Разность Rn и Rm, результат поместить в Rd

Применимы только регистры R0-R7

Изменяемые флаги: N, Z, C, V

sub r0,r1,r2;

SUB(4)

SUB SP,#<imm_7> * 4

SP := SP - #imm_7 << 2

Только значение кратное 4 и меньшее, чем 508 можно указывать в качестве вычитаемого.

Флаги не изменяются

sub sp,#16;

TST

TST <Rn>,<Rm>

CPSR flags:= Rn AND Rm 

Установка флагов в N Z результате операции AND между Rn и Rm. Результат операции не сохраняется. 

Применимы только регистры R0-R7

tst r0,r1;


 

No comments yet! Why don't you be the first?

Post Comment

Your email address will not be published. Required fields are marked *