В предыдущем сообщении я привёл список команд, с помощью которых можно запрограммировать любую процедуру. Однако осталось кое-что, о чём следует иметь представление, прежде чем делать свои первые шаги в программирования на ассемблере ARM. И речь идёт о регистрах процессора.
В отличие от Спектрума тут всё довольно просто - у процессоров есть 16 регистров, которые обозначаются как r0-r15, а также два специальных регистра - CPSR и SPSR. Собственно, на этом всё
Но, на самом деле, как обычно, есть нюансы. Их много, но я остановлюсь лишь не некоторых из них.
Начнём с регистров общего назначения. Как уже было написано выше их всего 16. И все они 32-х битные, то есть каждый из них может хранить 4 байта, и, соответственно, процессор за одну команду может оперировать с таким объёмом данных. Однако не всеми регистрами Rxx вы можете распоряжаться, как заходите. Некоторые из них имеют специальное назначение, а некоторые и вовсе недоступны из режима Thumb.
Первые 8 регистров (r0-r7) - это регистры общего назначения, которые доступны из любого режима процессора, не важно Thumb (CODE16) это или ARM (CODE32). Пять следующих регистров (r8-r12) доступны только из режима ARM. Остаётся ещё три регистра, которые отведены под специальные задачи и помимо традиционного обозначения r13-r15 имеют псевдонимы.
r13 (SP) - это указатель стека, такой же как на ZX Spectrum, только разрядностью побольше.
r14 (LR) - это, так называемый, регистр связи. Он необходим, например, для вызова подпрограмм. На ZX Spectrum, когда мы вызываем подпрограмму по команде CALL, адрес возврата записывается на стек. В процессорах же АРМ всё происходит несколько иначе - адрес возврата записывается не на стек, а как раз в этот самый регистр связи. Причём, если вы потом из подпрограммы вызовете ещё одну подпрограмму, то адрес возврата затрёт предыдущий и из первой подпрограммы вы уже не сможете вернуться. Вот поэтому при вложенных подпрограммах необходимо самому заботится о сохранении регистра LR и его своевременном восстановлении.
r15 (PC) - это программный счётчик. Тут без особенностей, он такой же, как на Z80.
Вот так будет нагляднее:
CPSR (Current Program Status Register) - это регистр, который хранит флаги, а также информацию для обработки прерывания.
SPSR (Saved Program Status Register) - этот регистр хранит копию CPSR при обработке прерывания. Опять же, для нас этот регистр пока неактуален, как и всё, что связано с прерываниями.
На прерываниях останавливаться не будем, а вот про флаги поговорить, безусловно, стоит. В общем-то почти все флаги нам знакомы по процессору Z80:
Q (Saturation) - насыщение/переполнение в DSP-операциях (для нас пока неактуально)
V (oVerflow) - переполнение (знаковое)
C (Carry) - перенос бита (беззнаковый)
Z (Zero) - нулевой результат (равенство)
N (Negative) - отрицательное значение (бит 31 установлен)
Именно благодаря флагам мы можем производить какие-то действия в программе, в зависимости от результата работы предыдущих команд. В таблице приведено обозначение условий:
Предикат
Отрицание Флаги Комментарий EQ NE Z == CS / HS CC / LO C >= (беззнаковое) MI PL N < 0 VS VC V переполнение HI LS zC > (беззнаковое) GE LT NV || nv >= (знаковое) GT LE NzV || nzv > (знаковое) AL - - Безусловная команда
Как и в Z80, здесь есть команда условного перехода, в качестве суффикса которой как раз используются обозначения условий из таблицы. И мы в программе "Hello, World!" уже использовали условный переход:
В первой строчке мы сравниваем содержимое регистра r3 с числом 10. А во второй команде, при условии BNE (branch if not equal - bne) мы переходим на метку loop. На Спектруме аналогом этой команды была бы команда jr nz,loop.Код:cmp r3,10 ; Сравниваем код символа с кодом перевода строки bne loop ; Переходим к следующему символу, если код символа не равен коду перевода
Любопытно, но по умолчанию почти все команды никак не затрагивают флаговый регистр. Вы можете до посинения вызывать команду SUB R1,1 и ожидать, что рано или поздно произойдёт обнуление регистра, сторожа его командой BEQ:
Однако вас будет ожидать разочарование - команда BEQ никогда не сработает. А всё потому, что флаговый регистр не будет реагировать на результат команды SUB. И вот чтобы флаговый регистр всё-таки отреагировал, вам необходимо явно указать, что вам требуется реакция флагового регистра. Делается это довольно просто - суффиксом S. То есть вместо SUB, вам нужно использовать команду SUBS.Код:mov r1,100 loop: sub r1,1 beq exit ; Данная команда никогда не сработает b loop exit:
В качестве бонуса, суффикс S вы можете использовать даже в команде MOV. То есть вот такая команда BEQ вполне себе сработает после MOVS:Код:mov r1,100 loop: subs r1,1 beq exit ; Команда сработает, когда в R1 будет 0 b loop exit:
Но и это еще не всё! Помимо команд условного перехода практически любая команда может быть исполнена по условию, заданному в суффиксе. Например, команда MOVEQ будет выполнена только, если результат предыдущей операции, влияющий на флаговый регистр, будет равен нулю:Код:movs r1,0 beq label ; Данная команда сработает
Правда, если вы дизассемблируете код вот с такими условными командами, то вы увидите, что компилятор добавил к ним одну или несколько команд IT, которые как раз позволяют процессору эти самые условия обрабатывать. То есть суффикс с условием транслируется в некоторую конструкцию команд IT. Это вас не должно никак беспокоить, если только вы не бьётесь за каждый байт исполняемого файла.Код:movs r1,0 moveq r2,1 ; Команда сработает movne r2,2 ; Команда не сработает
Думаю, что для начала этой информации о регистрах процессоров ARM вам будет достаточно.






Ответить с цитированием