Программирование ветвлений в ассемблере

Программирование микроконтроллеров PIC. Часть 5. Ассемблер. Организация циклов и ветвлений

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

Для начала давайте разберёмся, как организуются ветвления и что это такое. Ветвление — это такое место в программе, после которого в зависимости от какого либо условия может начать выполняться тот или иной код. То есть, счетчик команд в результате выполнения команды ветвления может быть установлен по двум различным адресам, в зависимости от исхода проверки какого-либо условия.

Для организации ветвлений в pic-контроллерах можно использовать 4 команды: две оперирующие с байтами (decfsz, incfsz) и две оперирующие с битами (btfsc, btfss). Работают эти команды следующим образом:

decfsz f,d - вычесть 1 из регистра f, если результат =0, то пропустить следующую команду (d определяет, куда сохранять результат, если d=0 - результат сохраняется в аккумуляторе W, если d=1 - результат сохраняется в регистре f) incfsz f,d - добавить 1 к регистру f, если результат =0, то пропустить следующую команду btfsc f,b - проверить бит b в регистре f, если он =0, то пропустить следующую команду btfss f,b - проверить бит b в регистре f, если он =1, то пропустить следующую команду

decfsz f,d — вычесть 1 из регистра f, если результат =0, то пропустить следующую команду (d определяет, куда сохранять результат, если d=0 — результат сохраняется в аккумуляторе W, если d=1 — результат сохраняется в регистре f) incfsz f,d — добавить 1 к регистру f, если результат =0, то пропустить следующую команду btfsc f,b — проверить бит b в регистре f, если он =0, то пропустить следующую команду btfss f,b — проверить бит b в регистре f, если он =1, то пропустить следующую команду

Читайте также:  Информатика программирование линейных алгоритмов конспект

Эти команды эквивалентны следующим алгоритмам:

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

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

Если провести аналогию с языками высокого уровня, то эти конструкции можно сравнить с конструкциями вида if then else и им подобными.

Может сложиться впечатление, что число условий для организации ветвлений очень ограничено (проверки на ноль содержимого регистра в результате сложения или вычитания + проверки отдельного бита в регистре). На самом деле нужно понимать, что информация в контроллере представлена битами и байтами и в любом случае все ваши действия отражаются в памяти контроллера изменением каких-либо битов или байтов, равно как и любое условие сводится к проверке каких-либо битов или байтов. Например, большинство логических и арифметических команд в процессе выполнения изменяют флаги регистра специального назначения STATUS, о настройках модулей контроллера и результатах их работы также сигнализируют различные биты в специальных регистрах. Значения всех этих битов могут использоваться в качестве условий для организации ветвлений.

Например, мы хотим проверить, равны ли между собой значения в двух регистрах А и В. Если равны, то пусть программа выполняется дальше, если нет — пусть счётчик команд устанавливается на адрес Y и программа продолжает выполняться с этого адреса.

Для реализации такого алгоритма можно воспользоваться, например, командой xor, которая изменяет флаг Z. Если А=В, то результат побитного исключающего ИЛИ между этими регистрами будет равен нулю и флаг Z в регистре STATUS установится в единицу:

Теперь давайте поговорим о циклах. Собственно, циклы — это повторение одного и того же участка кода заданное количество раз. В ассемблере для организации циклов нет специальных команд, подобных операторам for to , while do и прочим операторам языков высокого уровня. Давайте разберёмся почему.

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

Циклы бывают двух типов: с предпроверкой (или ещё говорят с предусловием), когда проверка условия происходит в начале цикла, и с постпроверкой (или по-другому — с постусловием), когда проверка условия происходит в конце цикла.

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

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

  1. Часть 1. Необходимые инструменты и программы. Основы MPLAB
  2. Часть 2. Что такое микроконтроллер и как с ним работать
  3. Часть 3. Структура программы на ассемблере
  4. Часть 4. Разработка рабочей части программы. Алгоритмы
  5. Часть 5. Ассемблер. Организация циклов и ветвлений
  6. Часть 6. Как перевести контроллер в режим программирования и залить в него прошивку

Понравилась статья? Поделись с друзьями!

Источник

Программирование ветвлений в ассемблере

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

Имитация конструкции if..else

Во многих распространеных языках высокого уровня есть конструкция if..else, которая в зависимости от условия выполняет те или иные действия. С помощью бейсикоподобного синтаксиса обобщенно эту конструкцию можно представить следующим образом:

IF условие THEN выполняемые действия, если условие верно ELSE выполняемые действия, если условие НЕ верно END IF

Или конструкция if..else в большинстве сиподобных языков

Например, сначала возьмем простейшую форму конструкции if, которая сравнивает два числа и, если они равны, устанавливает некоторую переменную. Например, на сиподобном языке это выглядело бы так:

Интуитивно мы могли бы определить подобную конструкцию на языке ассемблера следующим образом. Вначале указываются операторы, которые оценивают выражение — инструкция CMP . Если условие верно, выполняют переход, к метке, где выполняются собственно действия конструкции if. Если условие неверно, выполняем переход к метке, которая выступает в качестве завершения конструкции if. Пример:

.global _start _start: mov x0, #1 // устанавливаемый в конструкции if регистр mov x1, #2 // a = 4 mov x2, #4 // b = 4 begin_if: cmp x1, x2 // сравниваем два числа на неравенство b.eq equal // если x1 == x2, переход к метке equal b end_if // если x1 != x2 , то выходим из конструкции if equal: // собственно действия конструкции if add x0, x0, #1 // если x1 == x2, то x0 = x0 + 1 end_if: mov x8, #93 // номер функции Linux для выхода из программы - 93 svc 0 // вызываем функцию и выходим из программы

Здесь условная конструкция if располагается между метками begin_if и end_if . Допустим, мы хотим увеличить на 1 значение регистра Х0, если регистры Х1 и Х2 равны. Сначала сравниваем регистры Х1 и Х2 инструкцией CMP .

Далее проверяем условие EQ (что регистры Х1 и Х2 равны):

Если регистры равны, переходим к метке equal , на которую проецируются собственно действия конструкции if — увеличение значения в регистре Х0

equal: // собственно действия конструкции if add x0, x0, #1

Однако если условие не верно (числа Х1 и Х2 не равны), то инструкцией b выходим из конструкции if — переходим к метке end_if

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

.global _start _start: mov x0, #1 // устанавливаемый в конструкции if регистр mov x1, #4 // a = 4 mov x2, #4 // b = 4 begin_if: cmp x1, x2 // сравниваем два числа на неравенство b.ne end_if // если x1 != x2, то выходим из конструкции if add x0, x0, #1 // если x1 == x2, то x0 = x0 + 1 end_if: mov x8, #93 // номер функции Linux для выхода из программы - 93 svc 0 // вызываем функцию и выходим из программы

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

if..else

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

begin_if cmp X, Y // проверяем условие b else // переход к метке else, если условие не верно действия, если условие верно b end_if // выход из конструкции if else: действия, если условие не верно end_if:

Например, если условие верно, прибавим 1 к X0, а если не верно, вычтем 1:

.global _start _start: mov x0, #2 // устанавливаемый в конструкции if регистр mov x1, #4 mov x2, #4 begin_if: cmp x1, x2 // сравниваем x1 и x2 b.ne else_if // если условие не верно (x1 != x2) - к метке else_if add x0, x0, 1 // если x1 == x2 b end_if // в конец конструкции if else_if: // альтернативные действия, если условие не верно sub x0, x0, 1 // если x1 != x2 end_if: mov x8, #93 // номер функции Linux для выхода из программы - 93 svc 0 // вызываем функцию и выходим из программы

Здесь, если условие не верно (a и b не равны), то переходим к метке else_if, после которой определено альтернативное действие.

Источник

КТП / 5,6 Ветвления,циклы2

Ветвления в программе на ассемблере можно организовывать с помощью команд условного перехода, типа JX M или JNX M, т.е. условный переход на метку М (по адресу М), если (Х)=1 или (Х)=0 (см. систему команд, команды передачи управления), а также безусловного перехода JMP M.

Нет

Да

JNX M

JX M1

JMP M2

M1:

if X then Y1 else Y2

Нет

JNX M1

JMP M2

M1:

JX M1

JMP M2

M1:

Рассмотрим две логические структуры из языка высокого уровня Паскаль, типа if X then Y и if X then Y1 else Y2 (Х – логическое условие; Y,Y1,Y2- выполняемые действия) и организуем подобные структуры на ассемблере (таблица ).

Таблица — Организация ветвлений на Паскале и ассемблере

Ветвления в программе на ассемблере можно организовывать с помощью команд условного перехода, типа JX M или JNX M, т.е. условный переход на метку М (по адресу М), если (Х)=1 или (Х)=0 (см. систему команд, команды передачи управления), а также безусловного перехода JMP M.

Рассмотрим две логические структуры из языка высокого уровня Паскаль, типа if X then Y и if X then Y1 else Y2 (Х – логическое условие; Y,Y1,Y2- выполняемые действия) и организуем подобные структуры на ассемблере (таблица ).

Таблица — Организация циклов на Паскале и ассемблере

for I:=Imax downto Imin do S

Нет

Да

M:

DJNZ Rn, M

while X do S

Нет

Да

M1: JNX M2

JMP M1

M0: JX M1

JMP M2

M1:

repeat S until X

Нет

Да

M1:

JNX M1

M1:

X=1 JX M2

JMP M1

Источник

Оцените статью