Продолжаем знакомство с системами команд микроконтроллеров. Сегодня поговорим о командах перехода в целом и, более подробно, о командах безусловных переходов. Команды переходов называют еще командами передачи управления.
Команды переходов нужны не только для передачи управления в другую точку программы. Вызов подпрограмм и возврат из подпрограмм это тоже команды переходов. Кроме того, есть еще прерывания. Давайте посмотрим, какие вообще переходы бывают.
Типы переходов
Безусловные и условные переходы
Безусловные переходы обеспечивают передачу управления по заданному адресу независимо от каких либо условий. Можно сравнить такие команды переходов с оператором GOTO, который редко можно встретить в современных программах, но который раньше применялся повсеместно. Языки высокого уровня стали структурированными, а вот о командах процессоров такого сказать нельзя. Поэтому команды безусловной передачи управления остаются необходимыми.
Условные переходы обеспечивают передачу управления в зависимости от соблюдения одного, или нескольких, условий. Их можно сравнить с оператором IF, хотя аналогия будет не полной. Машинные команды условного перехода обычно выполняют проверку флагов состояния и выполняют переход, если условия соблюдены. Если же условия не соблюдены, то переход не выполняется.
Абсолютные и относительные переходы
Команды абсолютного перехода передают управление по адресу заданному операндом. То есть, заносят в регистр адреса команды PC значение своего операнда. Режим адресации при этом может быть разный, на суть это не влияет. Переход может быть длинным или коротким, но об этом чуть позже.
В командах относительного перехода адрес указывается относительно текущего значение регистра PC. Обычно, как число со знаком. Итоговый адрес, на который будет передано управление, получается в результате сложения (знакового) регистра РС и операнда команды. И вот тут возникают некоторые тонкости.
Дело в том, что регистр РС во время выполнения команды может содержать как ее адрес, так и адрес следующей за ней команды. В общем случае.
На рисунке я показал оба варианта для случая когда РС адресует команды целиком, а не отдельные байты. RJMP это некая абстрактная команда относительного перехода. Если вы пишете программу на ассемблере и не помните, как ведет себя регистр адреса команды в вашем процессоре и тонкости формирования итогового адреса перехода, используйте метки для задания адреса перехода. Это позволит избежать ошибок, которые не так просто обнаружить. То есть, вместо команды
RJMP $-5
лучше установить метку в нужном месте и написать
RJMP label
Это касается и простейших случаев, вроде зацикливания выполнения команды
goto $ ; работает не всегда
label: goto label ; работает всегда
Проиллюстрирую тонкости относительных переходов.
Для STM8 команды относительного перехода выполняются так
PC ← PC + 2+ rr
Обратите внимание, что здесь используется увеличенное на 2 содержимое PC к которому прибавляется смещение rr (операнд команды) со знаком. Кстати, если посмотреть в разделе с более подробным описанием работы команд, то мы увидим
PC <= PC + dst
что отражает суть относительного перехода, но не является верным с точки зрения работы команды на низком уровне.
Для AVR команды относительного перехода выполняются так
PC ← PC + k + 1
Обратите внимание, что здесь уже используется увеличенное лишь на 1 содержимое PC к которому прибавляется смещение k со знаком.
Для PIC18 все еще интереснее
(PC) + 2 + 2n => PC
Здесь не только используется содержимое РС увеличенное на 2, но и смещение умножается на 2! По причине того, что смещение задается в командах, а регистр РС работает с байтами (каждая команда занимает ровно 2 байта).
Думаю, я вас убедил не пытаться вычислять смещение в командах относительного перехода вручную. Лучше используйте метки и пусть компилятор выполняет все вычисления сам.
Длинные и короткие переходы
В современный микроконтроллерах адресное пространство программ может превышать возможность прямой адресации с помощью регистра PC. Кроме того, память может быть разбита на страницы или вообще находиться за пределами микроконтроллера (внешняя память).
Задавать в каждой команде перехода полный адрес несколько расточительно. Поэтому в некоторых случаях существует возможность указывать и как полный адрес, так и его часть в пределах единицы адресации (например, страницы) или некоторого небольшого диапазона. Обратите внимание, что я сейчас говорю о процессорах вообще, а не о конкретной модели микроконтроллера.
Вызов подпрограмм и прерываний
В отличии от простых переходов в этих случаях выполняются дополнительные действия - в стеке сохраняется адрес возврата. То есть, адрес следующей за командой перехода (вызова) команды.
В командах вызова подпрограмм указывается адрес, на который передается управление. Здесь могут быть некоторые особенности и ограничения, но целом все так же, как и в обычных команда перехода.
Про прерывания будет отдельная статья, возможно и не одна. Сейчас просто скажу, что в командах прерывания адрес напрямую не задается. Адрес задается вектором прерывания. Вектор может указываться неявно мнемоникой команды или задаваться в качестве операнда.
Вызываемые командами прерывания называются программными (software), в отличии от прерываний вызываемых аппаратурой, которые называются аппаратными (hardware). При возникновении прерывания выполняется еще больший, по сравнению с командами вызова подпрограмм, действий. Но об этом в отдельной статье.
Возврат и подпрограмм и прерываний
Как следует из названия, эти команды возвращают управление в точку вызова подпрограммы (помните, адрес возврата сохранялся в стеке?) или точку прерывания. Причем команда возврата из прерывания не делает разницы между программными и аппаратными прерываниями.
Команды безусловных переходов в рассматриваемых нами микроконтроллерах
Не смотря на множество вариантов переходов в реальности все не так страшно.
GOTO - безусловный переход в PIC. Да, для использования этой команды нужно помнить о страничной организации памяти программ. Кроме того, в разных моделях микроконтроллеров есть разница в разрядности PC.
BRA - относительный переход в старших моделях PIC (не PIC18).
BRW - относительный переход в старших моделях PIC (не PIC18). От команды BRA отличается тем, что смещение для перехода задается не в операнде, а хранится в WREG.
RJMP - относительный переход в AVR. Не смотря на то, что мнемоника команды совпадает ранее использованной мной в примере, это другая команда.
IJMP - косвенный абсолютный переход в AVR. Адрес перехода хранится в индексном регистре Z. Обратите внимания, что в моделях с памятью программ превышающей 128 кБ старшие разряды PC обнуляются. То есть, команда может осуществлять переход только в границах младших 128 кБ.
EIJMP - расширенный косвенный абсолютный переход в AVR. Отличается от IJMP тем, что старшие разряды PC не обнуляются, а заполняются содержимым EIND.
JMP - абсолютный переход в AVR в пределах 8 МБ памяти программ. Адрес перехода задается операндом. Команда есть не во всех моделях микроконтроллеров.
JRA - (jump relative always) безусловный относительный переход в STM8. А вот тут требуются некоторые пояснения, поскольку все не столь очевидно из документации. Дело в том, что эта команда имеет мнемонику-синоним JRT, которая относится к условным переходам. С точки зрения процессора это одна команда, так как их коды и формат полностью совпадают.
Зачем так сделано? С целью упрощения отладки! Отладчик легко может заменить "на лету" команду условного перехода (большинства команд условного перехода) на JRT или JRF для тестирования обоих веток проверки условия.
JRT - (jump relative true) как я уже сказал, это та же самая команда JRA. Мнемоника отличается лишь для семантического выделения того факта, что это фактически условный переход который выполняется всегда.
JRF - (jump relative false) относительный переход, который никогда не выполняется, в STM8. Опять таки, по своей сути это условный переход. Команда предназначена для целей отладки, для замены кода команды условного перехода отладчиком для исключения перехода.
Обратите внимание, что при написании программ мнемоники JRT и JRF обычно не используются! Вместо JRT используют мнемонику JRA. А вместо JRF... Ничего не используют, так как переход который никогда не выполняется вообще не нужен. Другое дело - отладка.
JP - абсолютный короткий (близкий) переход в STM8.
JPF - абсолютный длинный (дальний) переход в STM8.
Заключение
Вот мы и закончили краткое знакомство с командами переходов (передачи управления) вообще и командами безусловных переходов более детально.
Хорошо видно, что ничего особенно сложного тут не нет. Хотя особенностей все таки хватает. Особенно для STM8 с его специфическими JRT и JRF. Но надеюсь, что теперь вам не составит труда со всем этим разбираться.
В следующий раз мы познакомимся с командами условных переходов. Там все будет еще интереснее.
До новых встреч!