Микроконтроллеры PIC. Архитектура и программирование. Часть 3. Система команд и основы программирования микроконтроллеров PIC24F » Программирование устройств на PIC микроконтроллерах


Логин:
Пароль:
О сайте:

Pic.Rkniga.ru - Сайт как для начинающих, так и для опытных радиолюбителей, разрабатывающих свои устройства на популярных PIC микроконтроллерах.
Здесь можно обмениваться сообщениями на форуме, а также добавлять на сайт статьи и схемы своих устройств.

Меню сайта
Главная Форум по PIC микроконтроллерам Форум Статьи по PIC микроконтроллерам Статьи Справочная информаци по PIC микроконтроллерам Справочник Литература по PIC микроконтроллерам Литература Схемотехника Схемотехника устройств на PIC микроконтроллерах Микроконтроллеры Программаторы Все по программированию PIC микроконтроллеров Программы, Софт Программы Ссылки
Опрос

Какие микроконтроллеры вы используете?


Atmel
MicroChip
STM
Motorola
Texas Instruments
Другие


Последние материалы
  • Тестовая плата для отладки программ на микроконтроллере PIC18F4550
  • Кнопка On/OFF на PIC12F629.
  • Часы с синхронизацией от китайского будильника
  • ШИМ регулятор на PIC16F628A.
  • Счетчики прямого и обратного счета на PIC16F628A.
  • Таймер отключения питания для мультиметра и не только.
  • Измеритель напряжения и тока
  • Маршрутный компьютер для электровелосипеда
  • Простой двухканальный термометр на PIC16F690 и датчиках DS18B20
  • Электронная "Незабудка" для забывчивых
  • Популярные материалы
    Случайная книга
    Программирование устройств на PIC микроконтроллерах » Справочник » Микроконтроллеры PIC. Архитектура и программирование. Часть 3. Система команд и основы программирования микроконтроллеров PIC24F
    Микроконтроллеры PIC. Архитектура и программирование. Часть 3. Система команд и основы программирования микроконтроллеров PIC24F
    Автор публикации: alex Просмотров: 15470 Добавлен: 27-09-2012, 14:07 Комментарии: 0

    Содержание
    1. Обзор 16-битных PIC-микроконтроллеров
    2. Архитектура микроконтроллеров PIC24F
    3. Система команд и основы программирования микроконтроллеров PIC24F
       3.1 Программная модель микроконтроллеров PIC24F
       3.2 Режимы адресации и система команд
    4. Программирование портов ввода-вывода
       4.1 Аппаратно-программная архитектура портов ввода/вывода
       4.2 Программирование портов ввода/вывода
       4.3 Модуль регистрации событий
    5. Программирование прерываний
    6. Программирование таймеров
       6.1 Практическое использование 16-битных таймеров
       6.2 Работа таймеров в 32-битном режиме
    7. Интерфейс SPI микроконтроллеров PIC24F
       7.1 Аппаратно-программная реализация SPI в микроконтроллерах PIC24F
       7.2 Практическое программирование обмена данными по SPI
    8. Интерфейс I2C микроконтроллеров PIC24F
       8.1 Принципы функционирования интерфейса I2C
       8.2 Модуль интерфейса I2C микроконтроллеров PIC24F
       8.3 Практическое использование интерфейса I2C
    9.Программирование интерфейса PMP
       9.1 Режимы работы PMP
       9.2 Практические примеры программирования интерфейса PMP
    10. Последовательный интерфейс микроконтроллеров PIC24F
       10.1 Аппаратно$программная архитектура UART
       10.2 Практическое использование последовательного порта
    11. Обработка аналоговых сигналов в микроконтроллере PIC24F
       11.1 Программная модель интегрированного АЦП
       11.2 Практическое использование модуля АЦП
       11.3 Использование внешнего АЦП
    12. Генерация аналоговых и цифровых сигналов
       12.1 Модуль генерации цифровых сигналов
       12.2 Аналоговые компараторы в микроконтроллерах PIC24F

         Микроконтроллеры PIC24 представляют собой качественно новый тип устройств, разработанных фирмой Microchip. Программная архитектура этих микроконтроллеров существенно отличается от предыдущих семейств 8-битных устройств, хотя разработчики сделали все возможное, чтобы обеспечить безболезненный переход от 8-битной архитектуры к 16-битной.
         В этой главе рассматривается базовая программная модель микроконтроллеров PIC24F без учета особенностей реализации периферийных модулей, которые детально анализируются в последующих главах.

    3.1. Программная модель микроконтроллеров PIC24F

         Для разработчика программного обеспечения программную модель микроконтроллеров PIC24F можно представить так, как показано на Рис. 3.1.
         В качестве рабочих используются 16 регистров процессора (W), которые могут функционировать как регистры данных или адресов. Функция, выполняемая W-регистром, определяется режимом адресации, который используется в данной инструкции.
         В регистре W15 содержится указатель стека (Stack Pointer, SP), который автоматически модифицируется при обработке исключений, вызовов подпрограмм и прерываний. Тем не менее, регистр W15 можно использовать в инструкциях в качестве обычного рабочего регистра. Во многих случаях такое использование упрощает манипуляции с указателем стека. Бит 0 этого регистра всегда сброшен в 0 для выравнивания содержимого стека.
         При инициализации микроконтроллера в регистр W15 записывается значение 0x0800, и это обеспечивает установку указателя стека на начало области памяти, которая доступна пользователю. Программа пользователя может модифицировать SP так, чтобы он указывал на любую требуемую область памяти.
         Указатель стека всегда указывает на первое доступное слово и смещается при заполнении от младших адресов к старшим. Указатель стека всегда декрементируется перед извлечением значения из стека и инкрементируется после помещения значения в стек. Функционирование стека показано на Рис. 3.2.

    Рис. 3.1. Программная модель микроконтроллера PIC24F

         Когда содержимое счетчика команд помещается в стек, то биты 15…0 располагаются по первому доступному адресу в стеке, а биты 22…16 помещаются по следующему адресу, при этом старшие биты второго слова дополняются нулями.

    Рис. 3.2. Функционирование стека

         Процессор микроконтроллеров PIC24F имеет 16-битный регистр состояния (Status Register, SR). Младшая часть регистра состояния (SRL) содержит флаги арифметических операций (нуля, переноса, переполнения и знака), а также 3 бита приоритета (IPL2…IPL0), в которых устанавливается текущий приоритет прерываний процессора (см. Рис. 3.1).
         Регистр управления процессором (Core Control Register, CORCON) имеет всего 2 бита, которые можно использовать при разработке программ. Бит 3 (Interrupt Priority Status Level, IPL3) задает уровень приоритета прерываний процессора. Если этот бит установлен, то уровень приоритета прерываний процессора выше 7 — в этом случае пользовательские прерывания однозначно запрещены. Если этот бит сброшен, то уровень приоритета меньше или равен 7 — в этом случае прерывания пользователя могут быть разрешены. Бит 2 (Program Space Visibility, PSV) указывает на возможность доступа к памяти программ из памяти данных: если бит установлен, то заданная область памяти программ доступна из памяти данных, а если сброшен — недоступна.
         К программно-доступным регистрам ядра процессора микроконтроллеров PIC24F относятся еще два регистра, которые выполняют специальные функции и могут быть полезны при работе с блоками памяти и таблицами. Регистр TBLPAG используется для хранения старших 8 битов адреса памяти программ при операциях чтения/записи табличных данных. С помощью табличных инструкций процессора можно перемещать данные из памяти программ в память данных. Регистр PSVPAG (Program Memory Visibility Page Address Pointer) позволяет пользователю отобразить страницу памяти программ размером 2 Кбайт на верхние 32 Кбайт адресного пространства памяти данных. С помощью этого регистра можно получить доступ к секции констант программы.

    3.2. Режимы адресации и система команд

         Систему инструкций (команд) микроконтроллеров PIC24F можно разделить на несколько групп:
         • команды перемещения;
         • команды математических операций;
         • команды логических операций;
         • команды сдвига и циклического сдвига;
         • команды работы с битами;
         • команды сравнения/выбора;
         • команды условных переходов;
         • команды работы со стеком;
         • команды управления.
         Мы не будем подробно описывать функционирование каждой команды, а остановимся лишь на общих принципах реализации команд и используемых ими методах адресации. В этом разделе мы рассмотрим многочисленные примеры использования команд микроконтроллеров семейства PIC24F с применением различных методов адресации. Инструкции процессора в PIC24F могут быть регистровыми и адресными. Основное различие между этими типами инструкций состоит в том, что регистровые инструкции модифицируют содержимое регистров1, в то время как адресные инструкции используют содержимое рабочих регистров для доступа к данным, находящимся в памяти. В свою очередь адресные инструкции могут быть как с прямой регистровой адресацией (register direct addressing), так и с косвенной регистровой адресацией (register indirect addressing).
         Прямая регистровая адресация используется для доступа к содержимому 16 рабочих регистров W0…W15, причем обращение возможно как к целому слову (16 бит), так и к байту.
         Косвенная регистровая адресация применяется для доступа к любой ячейке памяти данных посредством формирования исполнительного адреса данных по содержимому одного или нескольких рабочих регистров. Таким образом, содержимое рабочего регистра или регистров является указателем на область памяти данных. Дополнительные возможности такого метода адресации обеспечиваются механизмами пред- и пост-инкремента содержимого регистра, что позволяет последовательно обрабатывать непрерывный диапазон адресов в памяти данных. Методы формирования эффективного адреса (ЕА) с помощью косвенной регистровой адресации показаны в Табл. 3.1.

    Таблица 3.1. Формирование эффективного адреса методом косвенной регистровой адресации
    Режим адресации Байтовая адресация Адресация слова Описание
    Косвенная без модификации EA = [Wn] EA = [Wn] Эффективный адрес формируется по содержимому регистра Wn
    Косвенная с постинкрементом EA = [Wn]+=1 EA = [Wn]+=2 Эффективный адрес формируется по содержимому регистра Wn, затем содержимое Wn инкрементируется
    Косвенная с постдекрементом EA = [Wn]–=1 EA = [Wn]–=2 Перед формированием эффективного адреса содержимое Wn инкрементируется
    Косвенная с прединкрементом EA = [Wn+=1] EA = [Wn+=2] Перед формированием эффективного адреса содержимое Wn
    Косвенная с преддекрементом EA = [Wn–=1] EA = [Wn–=2] Перед формированием эффективного адреса содержимое Wn декрементируется
    Косвенная со смещением, заданным в регистре EA = [Wn + Wb] EA = [Wn + Wb] Эффективный адрес формируется как сумма Wn и Wb
    Косвенная со смещением, заданным константой EA = [Wn + Slit5] EA = [Wn + 2*Slit5] Эффективный адрес формируется как сумма Wn и константы Slit5 (значение в диапазоне от –16 до +15)


         Регистр W0 является особым регистром, поскольку это единственный из рабочих регистров, который можно использовать в регистровых инструкциях.
         Регистровые инструкции оперируют с адресами памяти и содержимым регистра W0. Рабочие регистры W1…W15 в таких инструкциях в качестве приемника использовать нельзя. Регистровые инструкции обратно совместимы с инструкциями, которые входят в систему команд микроконтроллеров предыдущих семейств и работают только с одним W-регистром. Синтаксис ассемблера включает обозначение «WREG», призванное подчеркнуть, что регистр W0 используется в регистровой инструкции. Ниже приводятся примеры регистровых инструкций:

    mov WREG,0x0100
    add 0x0100,WREG

         Первая инструкция помещает содержимое регистра W0 по адресу 0x0100, а вторая складывает значение по адресу 0x0100 с содержимым регистра WREG и помещает результат в WREG.
         Все рабочие регистры отображены на адресное пространство памяти данных, поэтому их можно использовать в таких, например, инструкциях:

    mov 0x0004,W10

         Здесь 0х0004 — адрес регистра W2. Эта инструкция эквивалентна следующей:
    mov W2,W10

         Для более глубокого изучения различных режимов адресации и функционирования команд микроконтроллеров PIC24F мы рассмотрим многочисленные примеры программного кода, написанного на языке ассемблера MPLAB ASM30.
         В качестве целевого устройства будем использовать микроконтроллер PIC24FJ128GA010, хотя программы будут работать и с другими моделями семейства PIC24F.
         Изучение функционирования микроконтроллера на уровне команд ассемблера обязательно, если вы намерены стать высококвалифицированным разра ботчиком программного обеспечения. Даже если в дальнейшем вам придется разрабатывать программы на одном из языков высокого уровня (Си, Бейсик или Паскаль), знание языка ассемблера и программной архитектуры окажет неоценимую помощь при отладке программ. Зачастую, как показывает практика, без знания ассемблера бывает крайне сложно отладить программу, особенно сложную, до требуемого уровня функциональности. Очень часто знание ассемблера помогает решить те или иные проблемы, которые на языке высокого уровня решить довольно трудно (особенно это касается работы с внешними устройствами и интерфейсами). Разумное сочетание языка высокого уровня и ассемблера позволяет решить любую задачу в пределах аппаратных возможностей самого устройства.
         Компиляцию тестовых программ на ассемблере мы будем проводить в среде MPLAB IDE, а отладку проводить с помощью программного симулятора MPLAB SIM. Все тестовые программы на ассемблере разработаны с использованием шаблона, который показан далее:

    #include "P24FJ128GA010.inc"
      .data
         //данные
      .text
      .global reset
    __reset:
         //команды
    .end

         Все примеры из этой книги тестируются на микроконтроллере PIC24FJ128GA010, поэтому в шаблон включен заголовочный файл P24FJ128GA010.inc. Кроме того, во многих примерах используются инициализированные данные, которые объявляются в секции .data. Команды размещаются в секции программного кода .text. Исходный текст программы на ассемблере следует сохранить в файле с расширением .s, а сам файл включить в проект, созданный с помощью мастера проектов среды MPLAB IDE.
         Мы рассмотрим не все команды процессора, поскольку это заняло бы несколько сот страниц, а только часть из них. Детальную информацию обо всех инструкциях процессора читатели смогут найти в технической документации на микроконтроллеры PIC24F фирмы Microchip.

    3.2.1. Команды перемещения и адресация данных

         В командах перемещения, большинство из которых имеет мнемоническое обозначение mov, используется хотя бы один регистр. Регистровые инструкции могут использовать W-регистр как регистр данных или регистр, в который помещается смещение адреса. Рассмотрим несколько примеров.

    Пример 1

    mov #0x19C7,W0
    mov W0,W1

         В первой инструкции константа 0x19C7 командой mov помещается в регистр W0. Затем содержимое регистра W0 пересылается в регистр W1. Таким образом, после выполнения второй инструкции в регистре W1 будет содержаться значение 0x19C7.
    Пример 2

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:
    mov #0x1234,W0
    mov #d1,W1
    mov W0,[W1]
    L1:
    goto L1
    .end

         В этой короткой программе переменная d1 из секции инициализированных данных (директива .data) размещается по адресу 0x0800. В секции программы .text, которая начинается с метки main, первая команда mov помещает в регистр W0 константу 0x1234. Вторая команда mov помещает адрес переменной d1 (равный 0x0800) в регистр W1. Третья команда помещает содержимое регистра W0 по адресу, находящемуся в W1. Таким образом, после выполнения третьей команды mov в переменной d1 будет содержаться значение 0x1234.
    Пример 3

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    .text
    .global __reset
    __reset:
    mov #0x1234, W0
    mov #d1, W1
    mov W0, [W1++]
    add #0x3, W0
    mov W0, [W1]
    L1:
    goto L1
    .end

         Здесь показана методика использования пост-инкрементной адресации.
         В области данных проинициализированы две переменные – d1 и d2 с адресами 0х0800 и 0х802 соответственно. Как и в предыдущем примере, в регистр W0 помещается значение 0х1234, а в регистр W1 — адрес d1. В третьей команде mov в переменную d1, чей адрес содержится в регистре W1, помещается значение 0х1234, после чего содержимое W1 увеличивается на 2 (команда оперирует словами). Таким образом после выполнения команды регистр W1 будет содержать значение 0х0802, что соответствует адресу переменной d2.
         Команда add прибавляет значение 0х3 к содержимому регистра W0, так что перед последней командой mov регистр W0 будет содержать значение 0х1237.
         Наконец, следующая за add команда помещает это значение по адресу 0х0802, находящемуся в регистре W1.
    Пример 4

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    .text
    .global __reset
    __reset:
    mov #0x1234,W0
    mov #d2,W1
    mov W0,[W1—]
    add #0x3,W0
    mov W0,[W1]
    L1:
    goto L1
    .end

         Пример демонстрирует пост-декрементную адресацию. В регистр W1 командой mov заносится адрес переменной d2 (0x0802), по которому записывается значение 0х1234, затем содержимое W1 декрементируется, указывая на переменную d1 (адрес 0х0800). По этому адресу записывается значение 0х1237 из регистра W0.
    Пример 5

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    d3: .word 0x0804
    .text
    .global __reset
    __reset:
    mov #0x1234,W0
    mov #d2,W1
    mov W0,[++W1]
    add #0x7,W0
    mov W0,[W1]
    L1:
    goto L1
    .end

         В этой программе показано использование прединкрементной адресации.
         В регистр W1 командой mov заносится адрес переменной d2 (0x0802). Следующая команда предварительно увеличивает содержимое W1 на 2 (команда оперирует со словами), после чего помещает значение 0x123B из регистра W0 по адресу 0х0804.
    Пример 6

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    d3: .word 0x0804
    .text
    .global __reset
    __reset:
    mov #0x1234,W0
    mov #d2,W1
    mov W0,[—W1]
    L1:
    goto L1
    .end

         В этом примере показано использование преддекрементной адресации. Вторая команда mov помещает в регистр W1 адрес переменной d2. Следующая команда вначале декрементирует содержимое регистра W1, после чего помещает по адресу 0x0800, содержащемуся в этом регистре, значение 0х1234.
    Пример 7

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    d3: .word 0x0804
    .text
    .global __reset
    __reset:
    mov #0x4321,W0
    mov #d1,W1
    mov #4,W2
    mov W0,[W1+W2]
    L1:
    goto L1
    .end

         Программа демонстрирует применение косвенной адресации со смещением, заданным в одном из рабочих регистров. В качестве базового в данном случае выступает регистр W1, в который помещается адрес переменной d1, равный 0х0800 (вторая команда mov). Затем в регистр W2 заносится смещение 4.
         Наконец, последняя команда mov помещает содержимое регистра W0 по эффективному адресу, который формируется как сумма содержимого базового регистра W1 и регистра W2. Таким образом, эффективный адрес, по которому будет записано значение 0х4321, получается равным 0х0804, что соответствует переменной d2.
    Пример 8

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    d3: .word 0x0804
    .text
    .global __reset
    __reset:
    mov #0x4321,W0
    mov #d1,W1
    mov W0,[W1+2]
    L1:
    goto L1
    .end

         Данный пример демонстрирует использование косвенной адресации со смещением, заданным константой. Базовый адрес, равный адресу переменной d1, загружается в регистр W1. Последняя команда mov помещает содержимое регистра W0 по адресу, который формируется как сумма содержимого регистра W1 и константы 2 и будет равен 0x0802. Таким образом, эта команда запишет значение 0х4321 в переменную d2.
         В ряде случаев необходимо манипулировать с отдельными байтами слова или двойного слова. Для этого в командах перемещения используется суффикс b или q. В следующем примере показано, как записать байт в переменную, расположенную в памяти данных.
    Пример 9

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    .text
    .global __reset
    __reset:
    mov #0x4321,W0
    mov #d2,W1
    mov.b W0,[W1]
    L1:
    goto L1
    .end

         Замечу, что во всех командах, манипулирующих с байтами, по умолчанию изменяется младший байт. В этом примере для записи младшего байта (0x21) в младший байт переменной d2 используется инструкция mov.b, в которой применяется косвенная регистровая адресация посредством регистра W1.
         В следующем примере в переменную последовательно записываются младший и старший байты значения.
    Пример 10

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    .text
    .global __reset
    __reset:
    mov #0x1ACE,W0
    mov W0,d1
    mov #d2,W1
    mov #d1,W0
    mov.b [W0++],[W1++]
    mov.b [W0],[W1]
    L1:
    goto L1
    .end

         Первые две команды программы записывают значение 0х1ACE в переменную d1. Затем адрес переменной d1 помещается в регистр W0, а адрес переменной d2 — в регистр W1. В последних двух командах mov.b используется пост-инкрементная адресация для записи старшего байта переменной d1 в старший байт переменной d2.
         К командам перемещения данных относится и команда перестановки старшего и младшего байтов или полубайтов, которая эффективно используется в математических вычислениях. Следующий пример демонстрирует перестановку старшего и младшего байтов слова.
    Пример 11

    .text
    .global __reset
    __reset:
    mov #0x4,W1
    mov #0x9,W2
    add W1, W2,W0
    swap W0
    Loop1:
    bra Loop1
    .end

         Здесь содержимое регистров W1 (0x4) и W2 (0x9) складывается командой add W1, W2, W0 и результат (0xD) записывается в регистр W0. В 16-битном регистре W0 старший байт будет равен 0х0, а младший — 0xD. После выполнения команды swap W0 старший байт станет равным 0x0D, а младший — 0x0. Эту же программу можно модифицировать так, чтобы менять местами значения старшего и младшего полубайта младшего байта регистра W0, применив инструкцию swap.b. Исходный текст программы в этом случае будет выглядеть так:
    Пример 12

    .text
    .global __reset
    __reset:
    mov #0x4,W1
    mov #0x9,W2
    add W1,W2,W0
    swap.b W0
    Loop1:
    bra Loop1
    .end

         Перед выполнением команды swap.b в регистре W0 содержится значение 0x000D. После выполнения этой команды в регистре W0 будет содержаться значение 0x00D0.
         Аналогичным образом можно обменять и содержимое двух 16-битных рабочих регистров с помощью инструкции exch. Исходный текст простейшей программы, выполняющей обмен содержимым регистров W0 и W1, приведен ниже.
    Пример 13

    .text
    .global __reset
    __reset:
    mov #0x4,W1
    mov #0x9,W2
    exch W1,W2
    Loop1:
    bra Loop1
    .end

         В этой программе содержимое регистра W1 (0x4) пересылается в регистр W2, а содержимое регистра W2 (0x9) пересылается в регистр W1.

    3.2.2. Команды сравнения/выбора и условного перехода

         К этой группе команд относятся команды вида BTxx и CPxx, где аббревиатура BT означает «Bit Test», CP означает «Compare», а символы xx — одно из условий. О функциях команд легко догадаться по их названию. Команды BTxx проверяют состояние указанного бита (0 или 1) и по результатам проверки выполняют определенное действие. Команды CPxx выполняют сравнение значений операндов, в результате чего устанавливаются флаги в регистре состояния SR процессора. Дальнейшие действия выполняются с помощью команд условных переходов bra xx, где хх — условие выполнения перехода (с этими командами мы познакомимся при изучении примеров).
         Рассмотрим практические примеры использования этих команд.
    Пример 1

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #0xAAAA,W2
    mov W2,[W0]
    mov #0xFFFF,W1
    btss W1,#0
    Loop1:
    bra Loop1
    mov #0xFFFF, W2
    mov W2,[W0]
    Loop2:
    bra Loop2
    .end

         В этой программе в переменную d1 записывается значение 0хАААА, если бит 0 регистра W1 сброшен в 0, и значение 0хFFFF, если бит установлен в 1.
         В данном примере в регистр W1 заносится значение 0xFFFF, т.е. бит 0 будет установлен. Следовательно, в переменную d1 будет записано значение 0xFFFF.
         Если в регистр W1 поместить, например, значение 0xFFFE, то результат программы изменится и в переменную d1 будет записано 0xAAAA. Команда btss выполняет проверку бита 0 в регистре W1: если он равен 0, то выполняется следующая за btss команда, а если он равен 1, то следующая за btss инструкция пропускается. В этой программе команда bra выполняет безусловный переход на указанную в ней метку, образуя «вечный» цикл.
         Противоположным образом ведет себя инструкция btsc. В следующем примере показан модифицированный исходный текст программы из Примера 1, в котором вместо btss применяется инструкция btsc.
    Пример 2

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #0xFFFF,W2
    mov W2,[W0]
    mov #0xFFFF,W1
    btsc W1,#0
    Loop1:
    bra Loop1
    mov #0xAAAA,W2
    mov W2,[W0]
    Loop2:
    bra Loop2
    .end

         В этой программе инструкция btsc проверяет на равенство нулю нулевой бит регистра W1. Если он равен 0, то следующая команда пропускается и в переменную d1 записывается значение 0xAAAA; если бит установлен в 1, программа уходит на «вечный» цикл по метке Loop1, реализованный инструкцией безусловного перехода bra, при этом в переменной d1 остается значение 0xFFFF, как в данном конкретном случае.
    Пример 3

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #0xF,W2
    mov W2,[W0]
    mov #9,W0
    again:
    dec d1
    cp d1
    bra ge,again
    Loop1:
    bra Loop1
    .end

         В этой программе показан простой цикл по метке again, выполненный с применением команд dec, cp и bra ge, again. В начале каждой итерации цикла происходит декремент значения переменной d1, после чего команда cp сравнивает значение, записанное в рабочий регистр по умолчанию W0 (9), со значением в переменной d1. Команда cp изменяет, в зависимости от результата сравнения, младшие биты в регистре состояния процессора SR. Само сравнение выполняется методом вычитания содержимого рабочего регистра из содержимого переменной d1 во внутреннем цикле команды cp, так что значения операндов не меняются. Следующая за командой cp инструкция bra проверяет условие «больше-равно». Пока содержимое переменной d1 остается большим либо равным значению в W0, цикл повторяется. Как только значение в переменной d1 станет равным 8, произойдет выход из цикла.
         В этом примере у нас появилась команда условного перехода bra ge, again.
         Обратите внимание на синтаксис этой команды. После мнемоники инструкции (bra) следует условие в форме аббревиатуры (ge, Great than or Equal) и указывается метка перехода к программе, в случае если условие выполнено.
         В нашем случае инструкция bra анализирует биты состояния, установленные предыдущей командой cp.
         Команда cp имеет различные модификации, позволяющие организовывать циклы оптимальным образом.
    Пример 4

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #15,W2
    mov W2,[W0]
    again:
    dec d1
    cp0 d1
    bra gt,again
    Loop1:
    bra Loop1
    .end

         Здесь для реализации цикла используется инструкция cp0, которая выполняет сравнение значения переменной с нулем и устанавливает соответствующим образом биты регистра состояния SR. В переменную d1 помещается значение 15, после чего ее содержимое декрементируется в цикле again, пока не станет равным 0. Инструкция bra gt, again анализирует флаг нуля регистра SR и после его установки завершает цикл.
    Пример 5

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #15,W2
    mov W2,[W0]
    repeat #11
    dec d1
    Loop1:
    bra Loop1
    .end

         В этой программе демонстрируется использование еще одной весьма полезной инструкции условного перехода процессора repeat. Команда repeat имеет всего один операнд, представляющий собой число в диапазоне 0…16383, которое определяет, сколько раз выполнится следующая за командой repeat инструкция. В данном случае команда repeat будет выполнять следующую за ней инструкцию dec d1 11 раз. После выполнения команды repeat в переменной d1 будет содержаться значение 4, но инструкция dec d1 должна выполниться еще один раз, поскольку является очередной командой после repeat.
         В результате перед выполнением последней команды bra программы переменная d1 будет содержать значение 3. Подобные нюансы следует учитывать как при написании кода, так и при анализе дизассемблированных листингов.
    Пример 6

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #32,W2
    mov W2,[W0]
    call Increment
    Loop1:
    bra Loop1
    Increment:
    repeat #7
    inc d1
    return
    .end

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

    3.2.3. Команды работы с битами

         Команды работы с битами микроконтроллеров PIC24F, как следует из названия, предназначены для манипуляций с отдельными битами операндов. Такая возможность является весьма востребованной, поскольку в большинстве случаев системы на базе микроконтроллеров должны работать с отдельными сигнальными битами внешних устройств. Битовые команды позволяют анализировать состояние отдельных битов, что дает возможность организовать ветвления и переходы в программе, а также устанавливать или сбрасывать отдельные биты операнда.
    Пример 1

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #32,W2
    mov W2,[W0]
    bset.b [W0],#0
    bclr.b [W0],#5
    Loop1:
    bra Loop1
    .end

         Здесь в переменную d1 с адресом 0x0800 записывается значение 32 (0x20), затем команда bset.b [W0], #0 устанавливает бит 0 этой переменной, в результате чего содержимое d1 становится равным 33 (0x21). Следующая за ней инструкция bclr.b [W0], #5 сбрасывает бит 5 переменной d1, в результате чего окончательное значение переменной d1 будет равно 1. В этих командах была использована косвенная регистровая адресация посредством регистра W0, в котором хранится адрес переменной d1.
         Для быстрого анализа состояния отдельных битов переменной в систему команд микроконтроллеров PIC24F включены инструкции fbcl, ff1l и ff1r.
         Эти инструкции очень полезны в системах сбора данных при сканировании, например, сигнальных выводов периферийных устройств. Вот краткое описание этих инструкций:
         • fbcl — определяет изменение состояния битов от младшего к старшему (слева направо);
         • ff1l — находит первый ненулевой бит при проходе слева направо;
         • ff1r — находит первый ненулевой бит при проходе справа налево.
         Далее приведен пример использования инструкции ff1r.
    Пример 2

    .text
    .global __reset
    __reset:
    mov #8,W2
    ff1r W2,W3
    Loop1:
    bra Loop1
    .end

         В этой программе в регистр W2 заносится значение 8. Инструкция ff1r обнаруживает первый единичный бит в регистре W2 на позиции 4 (отсчет ведется от 1) и записывает это значение в регистр W3. Таким образом, регистр W3 будет содержать значение 4.
    Пример 3

    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #8,W2
    mov W2,[W0]
    ff1l W2,W3
    Loop1:
    bra Loop1
    .end

         В этой программе, в отличие от предыдущей, сканирование первого ненулевого бита в регистре W2 выполняется слева направо инструкцией ff1l.
         В этом случае позиция этого бита относительно старшего значащего бита будет равна 13 (0xD). Это значение и будет помещено в регистр W3.
         Среди команд битовых операций часто используются инструкции установки (bset, bset.b), сброса (bclr, bclr.b) и переключения (btg, btg.b) битов. Как правило, эти команды применяются для управления внешними исполнительными устройствами, подключенными к портам вывода микроконтроллера.
         Рассмотрим учебный пример генератора прямоугольных импульсов на выводе 0 порта A.
    Пример 4

    .text
    .global __reset
    __reset:
    mov #0x0,W0
    mov W0,TRISA
    clr PORTA
    again:
    btg PORTA,#0
    call Delay
    bra again
    Delay:
    clr TMR1
    mov #0x8010,W0
    mov W0,T1CON
    next:
    mov TMR1,W1
    cp W1,#0xAFFF
    bra le,next
    mov #0,W0
    mov W0,T1CON
    return
    Loop1:
    bra Loop1
    .end

         В этой программе бит 0 порта А переключается в противоположное состояние с интервалом времени, определяемым функцией задержки Delay. Таким образом, на выводе 0 порта А генерируются прямоугольные импульсы с периодом, равным Delay * 2. Эти операции выполняются в цикле

    again:
    . . .
    bra again

         Собственно переключение бита 0 порта А выполняет инструкция btg PORTA, #0. Для того чтобы это работало, порт А или, по крайней мере, его младший бит должен быть настроен как выход, что достигается сбросом соответствующих битов регистра-защелки TRISA в начале программы. Для реализации задержки в функции Delay используется 16-битный Таймер 1, который запускается на определенное время, определяемое константой в инструкции cp W1, #0xAFFF. Запуск Таймера 1 осуществляется посредством регистра T1CON.
    3.2.4. Команды сдвига и циклического сдвига

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

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:

    mov #d1,W1
    mov #0x8888,W2
    mov W2,[W1]
    mov #0x2,W0
    lsr d1
    Loop1:
    bra Loop1
    .end

         В этой программе в переменную d1 записывается значение 0x8888. Затем в регистр W0 помещается число, которое определяет количество сдвигов. Соответственно команда lsr d1 выполняет сдвиг вправо на 2 позиции, в результате чего в переменной d1 окажется число 0x2222.

    Пример 2

    .text
    .global __reset
    __reset:
    mov #0x17,W0
    lsr W0, #2,W1
    Loop1:
    bra Loop1
    .end

         В этом примере выполняется сдвиг содержимого регистра W0, которое равно 0x17, на 2 позиции вправо, а результат сохраняется в регистре W1. Таким образом, после выполнения команды lsr W0, #2, W1 в регистре W1 будет содержаться значение 0x5.
         В качестве демонстрационного примера рассмотрим реализацию операций целочисленного быстрого умножения при помощи команд сдвига и сложения.
         Такая возможность продемонстрирована в следующем примере.
    Пример 3

    .text
    .global __reset
    __reset:
    mov #0x4,W0
    mov W0,W2
    sl W0,#2,W1
    add W2,W1,W0
    Loop1:
    bra Loop1
    .end

         Нам нужно число 4, находящееся в регистре W0, умножить на 5 и результат записать в этот же регистр. Умножение на 5 можно представить в форме 2 x 2 + 1. Иными словами, можно выполнить два сдвига числа 4 влево, в результате чего получим 16, а затем прибавить число 4 к полученному результату. Команда сдвига sl W0, #2, W1 сдвигает число в регистре W0 на 2 позиции влево и записывает результат в регистр W1. Команда сложения add W2, W1, W0 складывает содержимое регистров W2 и W1 и записывает результат в регистр W0.
         В следующем примере содержимое порта А сдвигается влево, при этом анализируется бит 6 на равенство 1. Если в потоке битов, проходящих через 6-ю позицию, обнаруживается 1, то программа останавливается.
    Пример 4

    .text
    .global __reset
    __reset:
    mov #0x0,W0
    mov W0,TRISA
    mov W0,PORTA
    bset.b PORTA, #0
    again:
    mov #1,W0
    sl PORTA
    btsc PORTA,#6
    forever:
    bra forever
    call Delay
    bra again
    Delay:
    clr TMR1
    mov #0x8010,W0
    mov W0,T1CON
    next:
    mov TMR1,W1
    cp W1,#0x5
    bra lt,next
    mov #0,W0
    mov W0,T1CON
    return
    Loop1:
    bra Loop1
    .end

         В цикле again с помощью команды sl PORTA выполняется сдвиг влево на 1 бит содержимого порта А. Для команды sl величина сдвига задается в рабочем регистре W0 и в данном случае равна 1. Затем анализируется состояние бита 6 порта А: если он равен 1, то сдвиг влево прекращается, и программа входит в «вечный» цикл по метке forever. Если сдвигаемый бит не достиг 6-й позиции, то вызывается функция задержки Delay, после чего начинается следующая итерация цикла again. Таким образом, в программе будет выполнено 6 сдвигов, после которых в регистре-защелке порта А окажется значение 0х040.

    3.2.5. Команды математических и логических операций

         Микроконтроллеры семейства PIC24F обладают обширным набором инструкций для выполнения математических и логических действий над операндами. В АЛУ процессора предусмотрено выполнение 4 основных математических действий над целыми знаковыми и беззнаковыми числами: сложения, вычитания, умножения и деления. Для каждого из этих действий предусмотрен ряд инструкций, в которых используются различные типы адресации, делающие выполнение таких операций весьма эффективным. Все математические инструкции оперируют с целыми числами, знаковыми или беззнаковыми.
         Далее приведено несколько примеров использования этих инструкций.
    Пример 1

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #67,W1
    mov W1,[W0]
    mov #34,W0
    add d1
    Loop1:
    bra Loop1
    .end

         В этой программе используется одна из версий команды сложения, когда к содержимому ячейки памяти прибавляется содержимое рабочего регистра по умолчанию (W0). Сначала в переменную d1 записывается значение 67. Затем в регистр W0 заносится значение 34. Команда сложения add d1 к содержимому d1 прибавляет содержимое регистра W0, что дает в результате значение 101(0x65).
    Пример 2
    .text
    .global __reset
    __reset:
    mov #14,W0
    add W0,#7,W1
    Loop1:
    bra Loop1
    .end
         В этой программе команда add имеет 3 операнда. К содержимому регистра W0 прибавляется 7, и результат записывается в регистр W1. После выполнения операции там будет находиться значение 21 (0x15). Команды математических операций, как и рассмотренные нами команды перемещения, допускают использование прямой и косвенной регистровой адресации. В предыдущем примере в команде add была использована прямая регистровая адресация. Следующий пример демонстрирует использование косвенной регистровой адресации.
    Пример 3

    .data
    d1: .word 0x0800
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #7,W1
    add W1,#5,[W0]
    Loop1:
    bra Loop1
    .end

         В данном случае команда add складывает содержимое регистра W1 (0х7) с константой 5 и помещает результат по адресу, находящемуся в регистре W0, т.е. в переменную d1. После выполнения операции в d1 будет находиться значение 12 (0xC).
    Пример 4

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #7,W1
    mov #19,W2
    add W1,W2,[++W0]
    Loop1:
    bra Loop1
    .end

         В этом примере продемонстрировано применение косвенной регистровой адресации с прединкрементом при сложении содержимого двух регистров W1 и W2. В регистр W0 помещается адрес переменной d1 из секции .data, который перед выполнением сложения командой add инкрементируется. Таким образом, результат сложения, выполненного командой add, будет записан по адресу, следующему за адресом d1, т. е. в переменную d2. После выполнения операции в переменной d2 будет содержаться значение 26 (0x1A).
         В сочетании с командами условных/безусловных переходов, при помощи математических команд можно реализовать гибкие алгоритмы обработки данных, как это показано в следующих нескольких примерах.
    Пример 5

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    d3: .word 0x0804
    .text
    .global __reset
    __reset:
    mov #d1,W0
    mov #7,W1
    mov #19,W2
    repeat #2
    sub W1,W2,[W0++]
    Loop1:
    bra Loop1
    .end

         В этой программе в ячейки памяти d1…d3 помещается результат вычитания содержимого регистра W2 из содержимого регистра W1, которое равно –12 (0xFFF4). Для последовательного доступа к переменным d1…d3 применяется пост-инкрементная адресация с помощью регистра W0 в команде вычитания sub. Инструкция repeat обеспечивает выполнение следующей за ней инструкции вычитания sub 2 раза. Всего команда sub будет выполнена 3 раза.
         В результате выполнения этой программы в переменных d1…d3 окажется значение 0xFFF4. Подобный алгоритм при небольшой модификации можно использовать для заполнения области памяти каким-либо значением, например нулем.
         Несложно реализовать и алгоритм нахождения суммы элементов какой-либо области памяти, как это показано в следующем примере.
    Пример 6

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    d3: .word 0x0804
    cnt: .word 0x0806
    .text
    .global __reset
    __reset:
    mov #d1,W0
    push W0
    mov #7,W1
    mov W1,[W0++]
    mov #20,W1
    mov W1,[W0++]
    mov #10,W1
    mov W1,[W0]
    mov #cnt,W3
    mov #3,W0
    mov W0,[W3] ; cnt = 3
    pop W0 ; aa?an d1 -> W0
    clr W4 ; ?acoeuoao iaeaieeaaai a W4
    next:
    mov [W0++],W1
    add W1, W4,W4
    dec cnt
    cp0 cnt
    bra nz,next
    Loop1:
    bra Loop1
    .end

         В этой программе выполняется сложение содержимого ячеек памяти d1…d3, а результат сложения помещается в регистр W4. Переменная cnt выполняет функцию счетчика цикла next, в котором и выполняется операция сложения.
         В начале программы переменные d1…d3 инициируются следующими значениями: в d1 помещается число 7, в d2 — 20 и в d3 — 10.
         Инструкция push W0 сохраняет в стеке адрес переменной d1, который далее будет использоваться в качестве базового адреса при доступе к области памяти.
         Перед выполнением цикла next в счетчик cnt, адресуемый регистром W3, помещается количество итераций, равное 3, а регистр W4, в котором будет накапливаться результат, обнуляется командой clr W4. Кроме того, перед началом цикла next нам нужно восстановить содержимое регистра W0, а именно адрес переменной d1, что и выполняет команда извлечения из стека pop W0.
         Сложение чисел, содержащихся в переменных d1…d3, выполняется инструкцией add W1, W4, W4, при этом к предыдущему значению регистра W4 прибавляется содержимое регистра W1. Регистр W1 содержит значение текущей ячейки памяти, которое помещается в него командой mov [W0++], W1. Цикл выполняется до тех пор, пока значение счетчика cnt не станет нулевым. Это условие отслеживается командами

    cp0 cnt
    bra nz,next

         После выполнения цикла next в регистре W4 будет содержаться значение 37 (0x25). Два следующих примера посвящены операциям умножения и их реализации посредством инструкций процессора.
    Пример 7

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    .text
    .global __reset
    __reset:
    mov #d1, W0
    push W0
    mov #73, W1
    mov W1, [W0++]
    mov #20, W1
    mov W1, [W0]
    pop W0
    mov [W0++], W1
    mov [W0], W2
    mul.uu W1, W2, W4
    Loop1:
    bra Loop1
    .end

         В этой программе выполняется умножение чисел, содержащихся в переменных d1 и d2. Для умножения беззнаковых чисел используется инструкция mul.uu. В качестве операндов этой инструкции в данной программе выступают регистры W1 и W2, каждый из которых содержит сомножители, извлеченные из переменных d1 и d2 соответственно. В качестве приемника результата умножения выступает пара регистров W4…W5. Первым регистром приемника должен быть обязательно регистр c четным номером (в данном случае W4), в который помещается младший байт результата. Второй регистр приемника в команде явно не указывается, но его номер по умолчанию на 1 больше.
         В нашем случае это регистр W5, в который помещается старший байт результата. Если бы в качестве младшего регистра приемника использовался регистр W6, то старшим регистром в этом случае был бы W7 и т.д.
         В начале программы переменные d1 и d2 инициализируются значениями 73 и 20 соответственно. Для адресации этих переменных используется регистр W0.
         При указанных значениях переменных после выполнения операции умножения регистр W4 будет содержать значение 1460 (0x5B4).
         Для выполнения операций над числами со знаком необходимо использовать другую версию команды умножения, а именно mul.ss. Модифицируем предыдущий пример так, чтобы его можно было использовать для перемножения целых чисел со знаком.
    Пример 8

    .data
    d1: .word 0x0800
    d2: .word 0x0802
    .text
    .global __reset
    __reset:
    mov #d1,W0
    push W0
    mov #73,W1
    mov W1,[W0++]
    mov #-10,W1
    mov W1,[W0]
    pop W0
    mov [W0++],W1
    mov [W0],W2
    mul.ss W1,W2,W4
    Loop1:
    bra Loop1
    .end

         В этой программе перемножаются положительное число 73 (переменная d1) и отрицательное число –10 (переменная d2). Для умножения используется команда mul.ss, параметры которой имеют тот же смысл, что и в рассмотренной ранее инструкции mul.uu из предыдущего примера. Результат операции помещается в регистры W4 и W5, при этом в W5 будет содержаться 0, а W4 будет содержать значение 0xFD26, что соответствует отрицательному числу – 730, представленному в дополнительном коде.
         Группа математических команд содержит инструкции, позволяющие работать с многобайтовыми данными. Эти команды при выполнении операций учитывают флаг переноса, который мог быть установлен как следствие переноса или заема в результате операции с предыдущими словами. К таким инструкциям относятся addc и subb. При желании читатели смогут самостоятельно исследовать работу этих команд с помощью отладчика.
         Рассмотрим примеры использования группы команд логических операций.
         Эти команды позволяют выполнять булевые одноместные и двуместные операции. К таким операциям относятся хорошо известные двуместные операции логическое «И», логическое «ИЛИ», исключающее «ИЛИ» и одноместная операция отрицания «НЕ». В эту группу команд включены инструкции очистки (обнуления) операнда и установки, когда все биты операнда устанавливаются в 1. Инструкции, выполняющие операцию логического «И», имеют мнемоническое обозначение and, логического «ИЛИ» — ior, исключающего «ИЛИ» — xor. Что же касается операции отрицания «НЕ», то она реализована посредством инструкции com. Кроме того, в эту группу команд включена команда neg, позволяющая инвертировать знак числа. Инструкции логических операций весьма полезны при выделении и анализе отдельных битов операндов.
         Применение этих команд показано в следующих примерах.
    Пример 1

    .text
    .global __reset
    __reset:
    mov #0xFC,W0
    mov #0x13,W1
    and W0,W1,W2
    Loop1:
    bra Loop1
    .end

         Здесь выполняется операция логического «И» над операндами, помещенными в регистры W0 и W1. Команда and помещает результат операции в регистр W2. При указанных значениях операндов W0 и W1 итоговое значение в регистре W2 будет равно 0x10. Если инструкцию

    and W0, W1, W2

         заменить инструкцией ior W0, W1, W2 (логическое «ИЛИ»), то итоговое значение в регистре W2 станет равным 0xFF. При использовании в программе команды xor (исключающее «ИЛИ») в регистре W2 после выполнения операции будет содержаться значение 0xEF.
    Пример 2

    .text
    .global __reset
    __reset:
    mov #0xC, W0
    com W0, W1
    Loop1:
    bra Loop1
    .end

         В этом примере показано применение инструкции com. Эта инструкция инвертирует все биты исходного операнда. В данном случае инвертируется содержимое регистра W0 (0x000C), а результат, который будет равен 0xFFF3, помещается в W1.
    Пример 3

    .text
    .global __reset
    __reset:
    mov #0xFFF4, W0
    neg W0, W1
    Loop1:
    bra Loop1
    .end

         Программа инвертирует знак числа при помощи команды neg. Команда neg использует стандартный алгоритм получения инверсии числа: сначала все биты операнда инвертируются, затем к младшему биту прибавляется 1. В нашем примере при исходном значении операнда в регистре W0, равном 0xFFF4 (дополнительный код отрицательного числа –12), результат выполнения команды neg, помещенный в регистр W1, будет равен 0x000C, что соответствует положительному числу 12.
         Инструкцию neg можно использовать в программе для получения абсолютного значения (модуля) числа, как это показано в следующем примере.
    Пример 4

    .text
    .global __reset
    __reset:
    mov #0x81F4,W0
    mov W0,W1
    btsc W0,#15
    neg W0,W1
    Loop1:
    bra Loop1
    .end

         В этой программе с помощью инструкции btsc W0, #15 проверяется значение старшего бита числа. Если бит равен 0, то число в регистре W0 положительное и не нуждается в преобразовании. В этом случае следующая за btsc инструкция пропускается. Если же число в W0 отрицательное (старший бит установлен в 1), то команда neg преобразует его в положительное. В нашем случае число 0x81F4 — отрицательное, поэтому оно преобразуется командой neg к положительному значению 0x7E0C.

    3.2.6. Команды условных/безусловных переходов

         Команды этой группы предназначены для управления ходом вычислительного процесса и осуществляют переход к различным секциям программы по результатам проверки флагов состояния процессора. В предыдущих примерах программного кода мы уже использовали некоторые из этих команд, сейчас же остановимся на них более подробно.
         Наиболее широко при разработке программного обеспечения используются инструкции bra xx (xx — код условия), call и goto. Команда bra xx осуществляет переход по адресу программы, содержащемуся в теле инструкции, при выполнении условия xx. В общей сложности эта команда может проверять выполнение следующих условий:
    • C — установлен флаг переноса;
    • GE — больше или равно;
    • GEU — больше или равно для операций без знака;
    • GT — больше;
    • GTU — больше для операций без знака;
    • LE — меньше или равно;
    • LEU — меньше или равно для операций без знака;
    • LT — меньше;
    • LTU — меньше для операций без знака;
    • N — результат предыдущей операции отрицательный;
    • NC — перенос (заем) отсутствует;
    • NN — результат предыдущей операции неотрицательный;
    • NOV — переполнения нет;
    • NZ — результат предыдущей операции ненулевой;
    • OV — возникло переполнение;
    • Z — установлен бит нуля в регистре состояния. Например, команда bra z, label1 выполнит переход на метку label1 программы, если установлен бит Z в регистре состояния процессора. Кроме того, команда bra имеет две модификации, позволяющие выполнять безусловный переход:
    • bra iaoea, где метка должна находиться в пределах от –32768 до +32767 слов памяти программ относительно команды bra;
    • bra Wn, где Wn — рабочий регистр. К командам переходов относятся и команды вызова процедур call и безусловного перехода goto. Инструкции call и goto в качестве операнда могут использовать либо метку, либо один из рабочих регистров. Если в качестве адреса перехода использовать содержимое какого-либо из рабочих регистров, то с помощью одной инструкции bra или call можно организовать несколько ветвлений в программе, например, по принципу оператора switch…case языка Си. Рассмотрим несколько примеров подобного использования команд bra и call.
    Пример 1

    .text
    .glo

    Комментарии