Написание ассемблерных программ
Выбери формат для чтения
Загружаем конспект в формате pdf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
2. НАПИСАНИЕ АССЕМБЛЕРНЫХ ПРОГРАММ
2.1. Введение
Основные термины и определения
Инструментальные программные средства — программы, которые используются для
разработки других программ.
Ассемблер — программа, используемая для преобразования исходной программы на языке ассемблера в абсолютный или перемещаемый модуль.
Язык ассемблера – это символический машинно-ориентированный язык программирования. Программы на языке ассемблера транслируются непосредственно в команды микроконтроллера (микропроцессора). Следовательно, для эффективной записи ассемблерных
программ Вы должны быть знакомы как с архитектурой микроконтроллера, так и с языком ассемблера. Из сказанного следует, что язык ассемблера, являясь машиннозависимым языком, применим только к одному типу микропроцессора.
Программа, написанная на языке ассемблера, называется исходной программой.
Микропроцессор может выполнять только программу, представленную в двоичном коде,
называемым также машинным. Поэтому исходную программу предварительно следует
перекодировать (транслировать). Трансляция осуществляется программой, называемой
ассемблером. Для поддержания принципа модульного построения программы ассемблер
преобразует исходную программу в перемещаемый объектный модуль. В дальнейшем с
помощью программы редактора связей (компоновщика) этот модуль может быть скомпонован (один или с другими модулями) в программу, практически готовую к выполнению.
Командам (инструкциям) на ассемблере присваивают краткие буквенные обозначения
(мнемонические коды, мнемоники), образуемые из начальных букв английских слов, описывающих выполняемую командой операцию. Мнемоники ассемблера легче различаются
и запоминаются. Вы также можете символически выражать адреса и значения в поле операндов инструкций (команд). Поскольку вы назначаете эти имена, то вы можете сделать
их очень выразительными.
Если ассемблер допускает макрокоманды, то он называется макроассемблером. Применение макрокоманд позволяет группу команд записывать под обозначением программиста.
Кросс-ассемблер — ассемблер, при выполнении которого на одной машине формируется
программа в кодах другой машины.
Модульное программирование
Многие программы так велики или сложны, чтобы записывать их в виде единого целого
(файла). Программирование становится много проще, когда код поделен на небольшие
функциональные единицы (модули). Модульные программы обычно легче кодировать,
отлаживать и изменять, чем монолитные программы.
Модуль — независимо хранимая и транслируемая программная единица.
Модульный подход к программированию подобен проектированию аппаратного средства,
содержащего многочисленные схемы. Устройство или программа логически разделяется
на «черные ящики» с заданными входами и выходами. Как только интерфейсы между модулями определены, детальная разработка каждого модуля может производиться независимо.
1
Выгодами модульного программирования являются:
1. Эффективная разработка программы: программы могут быстрее разрабатываться при
модульном подходе, т.к. небольшие подпрограммы легче понимать, проектировать и тестировать,
чем большие программы. При определенных входах и выходах программист может задать на вход
необходимые данные и проверить корректность модуля, изучая выход. Независимые модули затем
компонуются редактором связей в единый абсолютный исполняемый программный модуль. В заключение этот модуль тестируется в целом.
2. Многократное использование подпрограмм: код, написанный для одной программы,
часто оказывается полезным в других программах. Модульное программирование позволяет эти
части сохранить для будущего использования. Поскольку код является перемещаемым, сохраненные модули могут быть связаны с любой программой, которая полностью удовлетворяет входным и
выходным требованиям модулей. При монолитном программировании такие части кода спрятаны
внутри программы и не так доступны для использования другими программами.
3. Легкость отладки и модификации: модульные программы, как правило, легче отлаживать,
чем монолитные программы. Благодаря хорошо определенным интерфейсам модулей программы,
проблемы могут быть изолированы в отдельных модулях. Как только неисправный модуль идентифицирован, фиксирование проблемы становится значительно проще. Когда требуется модифицировать программу, модульное программирование упрощает эту работу. Вы можете связывать новые
или отлаженные модули с существующей программой с уверенностью, что остальная часть программы не изменится.
Инструментальные средства фирмы Keil
Для оптимальной поддержки различных производных микроконтроллеров семейства 8051
фирма Keil предлагает ряд инструментальных средств.
исполняемый файл
облегченный вариант
редактор связей
библиотекарь
Макроассемблер A51 — ассемблер, который транслирует исходные ассемблерные программы (расширения файлов – *.a51, *.asm) для семейства x51 в объектные файлы (*.obj).
Эти объектные файлы затем компонуются или связываются при помощи компоновщика
(редактора связей) BL51 чтобы сформировать исполняемый абсолютный объектный модуль. Архив объектных файлов модулей представляется как библиотека этих файлов. Далее абсолютные объектные модули могут быть преобразованы в Intel HEX-файлы, пригодные для загрузки в ваше целевое устройство (микроконтроллер), симулятор или внутрисхемный эмулятор (ICE). Стоит отметить, что редактор связей из библиотечных файлов
выбирает, а затем и компонует программу только из тех подпрограмм, которые находятся
в библиотеке по ссылке. Файл с описанием «карты памяти» программируемого микроконтроллера имеет расширение «*.m51». Отчет о проделанной работе можно представить в
форме т.н. «листинга» (*.lst).
ISP — программирование в системе
IAP — программирование «самого себя»
Схема создания программы с помощью инструментальных средств фирмы Keil представлена на рис. 2.1. Эти средства входят в IDE Vision2 – Vision4 фирмы Keil.
2
Рис. 2.1. Схема создания программы инструментальными средствами фирмы Keil
2.2. Виды и синтаксис ассемблерных предложений
Исходные файлы ассемблерных программ содержат предложения, которые могут включать:
машинные инструкции (команды микропроцессора);
макровызовы (макрокоманды);
директивы ассемблера;
управляющме директивы (Controls – средства управления; управляющая конструкция) ассемблера;
На строке должно располагаться точно одно предложение. Предложения могут начинаться с любой колонки. Аргументы и операнды инструкций должны отделяться от средств
управления, директив и инструкций, по крайней мере, одним пробелом. Все ассемблерные программы должны завершаться директивой END. Эта директива сигнализирует ассемблеру, что это конец ассемблерной программы. Любая ассемблерная конструкция после этой директивы игнорируется. Самая короткая допустимая ассемблерная программа
содержит только директиву END.
Директивы управления
Управляющие ассемблерные директивы направляют работу ассемблера при генерировании файла листинга и объектного файла. Обычно эти конструкции не влияют на код, генерируемый ассемблером. Только управляющие конструкции условного ассемблирования
будут влиять на генерируемый код. Управляющие директивы могут быть указаны в командной строке или внутри исходного ассемблерного файла, где они предваряются знаком «$» (Например, $NOMOD51).
Директивы
Обычные директивы (псевдокоманды) ассемблера указывают программе ассемблер как
обрабатывать последующие инструкции языка ассемблера. Кроме того, директивы предоставляют вам способ определения программных констант и резервирования памяти для
переменных.
Макровызовы
Применение макрокоманд позволяет группу команд записывать под обозначением программиста.
3
Инструкции
Инструкции языка ассемблера специфицируют (определяют) код программы. Ассемблер
A51 транслирует инструкции программы в машинный код и сохраняет результирующий
код в перемещаемом объектном файле.
Ассемблерные инструкции имеют следующий обобщенный формат:
[Label:] [Mnemonic] [Operand_1] [, Operand_2] ... [; Comment]
Label: — метка — символическое имя, значение которого равно текущему значению адреса, на котором размещена инструкция;
Mnemonic — мнемоника команды микропроцессора — текстовая строка из ASCIIсимволов, которая представляет инструкцию машинного языка (команду);
Operand_X — операнд — аргумент который требуется специфицированной мнемонике.
Comment — комментарий — дополнительное текстовое описание или объяснение. Комментарий может содержать любой текст. Ассемблер игнорирует комментарии.
2.3. Основные структурные элементы ассемблерного предложения
2.3.1. Символические имена
Символическое имя (имя) — это имя, которое определяется для представления значения,
текстового блока, адреса или имени регистра. Вы также можете использовать имена для
представления числовых констант и описания выражений. Все символические имена могут содержать до 31 символа из следующего списка: 0 – 9, A – Z, a – z, _, ?
Имя может начинаться с любого символа, исключая цифры. В именах символы верхнего
и нижнего регистров не различаются.
2.3.2. Метки
Метка определяет «место» (адрес) в вашей программе или области данных. Метка должна
завершаться символом двоеточия (« : »), который идентифицирует метку. Когда метка определена, то она принимает текущее значение счетчика адреса (СА) активного сегмента.
Т.е. значение метки есть адрес. Метки могут иметь отношение (ссылаться) к программному коду, области переменных во внутренней или внешней памяти данных, или ссылаться
на данные-константы в области программы (кода). Доступ к объекту осуществляется через метку. Для изменения выполнения программы используются метки. Метки нельзя переопределить. В одном модуле файла не может быть двух одинаковых меток. На одной
строке может располагаться только одна метка.
2.3.3. Комментарий
Это текстовые строки, которые вы можете включить в вашу программу для идентификации и объяснения программы. Комментарий предваряется символом точки с запятой («;»).
Комментарии могут занимать часть строки или всю строку. Комментарии не влияют на
генерирование объектного файла или содержащийся там код.
Макроассемблер A51 имеет стандартный Си-препроцессор, который почти идентичен препроцессору Сикомпилятора C51. Поэтому комментарий можно начать с пары символов /* и завершить парой символов */.
Комментарий может содержать любое число строк, начинаться и заканчиваться в любом месте программы.
Однако в этом случае ассемблер не включает комментарий в листинговый файл, он полностью игнорируется
ассемблером.
4
2.3.4. Операнды
Это аргументы или выражения, которые указываются в ассемблерных директивах или инструкциях. Ассемблерные инструкции поддерживают более широкое разнообразие операндов, чем директивы. Некоторые инструкции не требуют операндов, а другие могут
требовать до трех операндов. Несколько операндов разделяются запятыми. Операнды в
инструкциях могут быть шести типов:
Тип операнда
Непосредственные данные (Immediate Data)
Прямые адреса битов (Direct Bit Addresses)
Программный адрес (Program Address)
Прямоадресуемые данные (Direct Data Addresses)
Косвенные адреса (Indirect Addresses)
[ @R0, @R1, DPTR, … ]
Специальные (зарезервированные) символические
имена ассемблера (Special Assembler Symbol)
Описание
Символические имена или константы, используемые как числовые значения
Символические имена или константы, которые указывают адрес бита (ссылаются на адрес бита)
Символические имена или константы, которые указывают адрес кода
Символические имена или константы, которые указывают адрес данных
Косвенная ссылка (указатель) на ячейку памяти,
возможно со смещением (используются регистры)
пример: MOV A, @R0 ↔ A ≔ [R0]
Имена регистров
Специальные символические имена ассемблера
Это зарезервированные имена регистров.
Регистр
A
DPTR
PC
C
AB
R0 – R7
AR0 – AR7
Описание
Аккумулятор микроконтроллеров семейства 8051
16-разрядный указатель данных, используемый для косвенной адресации в памяти типа
XDATA или CODE
16-разрядный программный счетчик (счетчик команд). Он содержит адрес следующей инструкции, которая должна быть выполнена
Бит (флаг) переноса
Регистровая пара, используемая в инструкциях умножения (MUL) и деления (DIV)
Восемь 8-разрядных регистров общего назначения текущего (активного) банка регистров
Абсолютные адреса регистров R0 – R7 текущего банка, которые указывается с помощью
директивы USING
пример: USING 2
MOV AR0, #0 ; здесь регистры не переключаются
Непосредственные данные
Операнд непосредственных данных – числовое выражение, которое кодируется как часть
машинной инструкции. Значения непосредственных данных используются литерально
(буквально) в инструкции, чтобы изменить содержимое регистра или ячейки памяти. Знак
«#» должен предшествовать любое выражение, которое должно использоваться как операнд непосредственных данных.
Доступ к памяти
Доступ к памяти – это запись или чтение значения в/из различных областей (пространств)
памяти. При прямом доступе (адресации) к памяти адрес памяти кодируется в инструкции
чтения или записи. При косвенном доступе к памяти используется содержимое регистра,
указанного в инструкции чтения или записи. В зависимости от способа доступа к памяти
последняя подразделяется на классы: DATA, BIT, IDATA, XDATA, CODE.
5
DATA
Ячейки памяти класса DATA могут адресоваться как прямо, так и косвенно. Емкость этой
памяти – 128 байт. РСФ, имеющие адреса, начиная с 0x80 и выше, допускают только прямую адресацию.
BIT
Битовые ячейки в памяти класса BIT адресуются с помощью битовых инструкций. Емкость этой памяти – 128 бит (16 байт). Кроме того, эти же инструкции применимы к РСФ с
побитовой адресацией.
IDATA
Переменные в этом классе памяти доступны через регистры R0 и R1. Емкость этой памяти – 128 (256) байт. Доступ к переменным этого класса памяти осуществляется через регистры R0 и R1.
XDATA
Доступ к ячейкам памяти класса XDATA осуществляется с помощью команды MOVX через регистр DPTR. Одна страница, размером 256 байт, может быть доступна через регистры R0 и R1.
CODE
Доступ с памяти класса CODE – с помощью инструкции MOVC через регистр DPTR или
PC.
Программные адреса
Программные адреса — это абсолютные или перемещаемые выражения с классом памяти
CODE.
Обычно программные адреса используются в инструкциях JUMP и CALL. Для косвенных переходов и вызовов подпрограмм требуется загрузить программный адрес в регистр
или таблицу переходов.
Двум обобщенным мнемоникам CALL и JMP не соответствуют никакие индивидуальные
коды инструкций. JMP может ассемблироваться в SJMP, AJMP или LJMP. CALL может
ассемблироваться в ACALL или LCALL. Эти обобщенные мнемоники всегда приводятся
к инструкциям, необязательно самым коротким, которые будут достигать (доставать) указанный операнд типа программный адрес.
— вызов подрограммы
автоматически
— переход
2.4. Система команд
Систему команд удобно разделить по функциональному признаку на 5 групп:
команды передачи управления;
команды арифметических операций;
команды логических операций;
команды передачи управления;
команды операций с битами (команды битового процессора).
6
Большинство команд имеют формат один или два байта и выполняются за один или два
машинных цикла. Первый байт команды любого типа и формата всегда содержит код операции. Второй и третий байты содержат либо адреса операндов, либо непосредственные
операнды.
В таблице перечислены команды, при выполнении которых модифицируются флаги результатов. В таблице отсутствует флаг паритета P, т.к. его значение изменяется всегда командами, изменяющими содержимое аккумулятора. Кроме того, флаги модифицируются
командами, в которых местом назначения результата является регистр PSW или его биты,
а также командами операций над битами.
2.4.1. Команды передачи данных
Большая часть команд этой группы – команды передачи и обмена байтов во внутреннем
ОЗУ. Их обобщенная мнемоника: MOV dest-byte, src_byte; dest-byte := src_byte.
Способы адресации данных (определение — пример):
- прямая (direct) — MOV direct, #...,
- непосредственная (immediate) — direct, direct,
- косвенная (indirect) — …, direct,
- неявная (implicit).
Пример:
@R0
[R0] ≔ A
R0 := R0 + 1
R7 := R7 – 1
А
R7 = 0, нет
да: конец
@R1
При прямой адресации указанный в команде адрес представляет собой машинный адрес операнда [1].
При прямой адресации адрес операнда содержится в теле самой команды. Например: MOV A, Rn. Номер
регистра текущего банка указывается в трех младших битах кода операции. Пример с ячейкой и РСФ [2].
В случае непосредственной адресации в поле адреса команды помещается значение операнда. [1].
В случае непосредственной адресации операнд располагается в теле команды. Например, второй байт команды: MOV A, #3 (КОП = 74H; команда MOV A, 3 имеет КОП = E5H) [2].
Косвенная адресация – способ адресации, при котором исполнительный адрес (адрес операнда) равен содержимому по адресу, указанному в команде [3].
Неявная адресация – способ адресации, при котором один или несколько операндов находятся в фиксированных для данной команды регистрах и не требуют явного указания в команде [3].
Неявная адресация – способ адресации, при котором в коде операции содержится неявное указание на один
или несколько операндов. Часто таким операндом является аккумулятор [2].
Центральным операндом здесь является аккумулятор. Обращение к нему может быть выполнено с использованием неявной и прямой адресации. В первом случае используется
имя A, во втором – ACC. Использование неявной адресации эффективнее. Запрещена команда MOV A, ACC. Возможна также передача данных без участия аккумулятора.
Далее рассматриваются команды до MOV DPTR, #data16 ; data16 — 16-ти разр. число
7
Замечание по команде MOV DPTR, #data16: как расположены в памяти слова и другие
«длинные данные»?
Считывание из памяти программ: MOVC A, @A+base_reg
Загружает в аккумулятор байт программного кода или константу из программной памяти.
Адрес – сумма беззнакового 8-битового содержимого аккумулятора плюс содержимое 16битового базового регистра, в качестве которого выступает DPTR или PC. В последнем
случае PC инкрементируется перед сложением с аккумулятором. В альтернативном варианте содержимое базового регистра не изменяется.
считывание из ПЗУ в аккумулятор
Пример. Программа преобразования двоично-десятичной цифры в семисегментный код:
входной параметр — код двоично-десятичной цифры передается через
аккумулятор
BCD_TO_7SEG: INC
A
MOVC A,@A+PC
RET
DB 3FH, 06H,
..., 6FH
загрузка таблицы в DPTR
BCD_TO_7SEG: MOV
DPTR,#Tbl_7Seg
MOVC A,@A+DPTR
RET
Tabl_7Seg:
DB
3FH, 06H,
..., 6FH
D7 D6 D5 D4 D3 D2 D1 D0
1
1
1
1
1
1 3FH
1
1
1
0 06H
… … … … … … … … … …
9
1
1
1
1
1
1 6FH
MOVX — доступ к внешнему ОЗУ;
MOVX A, @Ri — -//- через аккумулятор
MOVX A, @DPTR — в аккумулятор через DPTR;
MOVX @Ri, A — из аккумулятора по адресу, который указывает Ri;
MOVX @DPTR, A — из аккумулятора по адресу, который указывает DPTR.
Обращение к внешней памяти данных: MOVX dest_byte, src_byte (External MOV+X).
Передает данные между аккумулятором и байтом внешней памяти данных. Последняя адресуется только косвенно через 8-разрядные регистры R0, R1 или 16-разрядный DPTR.
— запись в стек
— только прямая адресация
— считывание из стека
PUSH ACC — заполнить аккумулятор (адрес, AR0-AR7)
POP ACC — восстановление аккумулятора.
8
Пример:
MOV SP, #STACK-1 ; STACK — сегмент стека
7 ← SP —указатель стека
область для переменных
Допускается только прямоадресуемый операнд. Нельзя применить R0, R1, … . Но, используя директиву «USING Банк» и зарезервированные имена AR0 и т.д., можно записать:
PUSH AR0
…
POP AR0
Пример:
USING 1 — использовать 1-ый банк;
PUSH AR0 — взять 8-ую ячейку и поместить ее содержимое в стек.
XCH — обмен данными
XCH A, Rn — обмен содержимым регистра;
XCH A, direct — -//- прямая адресация
XCH A, @Ri — -//- косвенная адресация
Пример:
XCHD A, @Ri
A
A
@Ri
R7
2.4.2. Команды арифметических операций
Команды сложения (вычитания): ADD A, SRC_BYTE ; A ≔ A + SRC_BYTE
ADDC A, SRC_BYTE ; A ≔ A + SRC_BYTE + C — сложение с переносом (если он есть,
то добавится «1», если нет, то «0»)
SUBB A, SRC_BYTE ; A ≔ A - SRC_BYTE - C, где С — заём (вычитание всегда с заёмом)
Особенность этих команд – одним из операндов и операндом назначения является аккумулятор. При этом второй операнд допускает все виды адресации, используемые в семействе MCS-51 для внутренней памяти данных.
9
Чтобы зафиксировать переполнение в беззнаковых числах, после последнего сложения
надо тестировать бит CY. Для знаковых чисел требуется использовать бит OV. Если перенос из 7-го бита, CY = 1, иначе CY = 0. Когда имеется только один перенос из 6-го или из
7-го бита, флаг OV = 1; в других случаях OV = 0.
Пример. Многобайтное сложение:
R6
R7
R4
R5
MOV A, R7
ADD A, R5 ; сложение младших байтов
MOV R7, A
MOV A, R6
ADDC A, R4 ; сложение старших байт (с переносом)
MOV R6, A
Заметим, что команда вычитания только с заемом. Как сделать вычитание без заема?
Пример. Вычитание без заёма [C = 0]:
CLR C
SUBB A, R7
Инкременты/декременты (простейшие арифметические операторы): INC/DEC
Допускаются прямая и неявная адресации.
Регистр DPTR можно только инкрементировать.
Пример:
ADD A, #1 ; здесь бит переноса вырабатывается
INC A ; а здесь нет
INC DPTR
Умножение/деление: MUL/DIV
Операнды (целочисленные) должны располагаться в регистрах A и B, а результат окажется там же, причем в В – старший байт, в А – младший. При этих командах бит переноса С
всегда сбрасывается в ноль. MUL – беззнаковое умножение. Если произведение > 255, то
OV = 1, иначе OV = 0, а CY = 0. DIV – беззнаковое деление. Изначально CY = OV = 0.
Результат деления получается дробным — целая часть в А, остаток в В. Если B = 0, то получается неопределенный результат, т.е. A и B не определены (OV = 1). Это самые длительные команды (4 машинных цикла).
Десятичная коррекция аккумулятора: DA A
Корректирует BCD-упакованный (двоично-десятичными) код после двоичного сложения.
Если младшая тетрада аккумулятора больше 9 или AC = 1, то ACC := ACC + 6 – будет
скорректирована младшая тетрада. Если после этого CY = 1 или старшая тетрада больше
9, то прибавляется 6 к старшей тетраде. Это опять приводит к выработке значения CY
10
(если CY = 1, то сумма больше 100). Таким образом, в зависимости от условий к ACC
может прибавляться 00H, 06H, 60H, 66H.
Примечание: Команда DA A правильно работает только после команд сложения.
2.4.3. Команды логических операций
Логическое «И», «ИЛИ», «ИСКЛЮЧАЮЩЕЕ ИЛИ»: ANL/ORL/XRL
Обобщенная мнемоника «И»: ANL dest_byte, src_byte ; dest_byte := dest_byte ^ src_byte
В большинстве вариантов команды одним из операндов и операндом назначения является
аккумулятор. Хотя такую же роль может исполнять прямоадресуемая ячейка памяти или
РСФ. Эта команда эффективна, когда требуется выполнить операцию «И» над группой
битов байта. Часто она используется для избирательного сброса битов в байте. «Наложить
маску» — логическая операция с константой.
0 0 0 0
сброс в ноль
Пример: ANL A,#0FH
ANL P1,#03H
0 0 0 0
Обобщенная мнемоника «ИЛИ»:
Х Х Х Х
останутся без изменений
Р1
Х Х Х Х
ORL dest_byte, src_byte ; dest_byte := dest_byte src_byte
Варианты операндов те же. Эта команда эффективна, когда требуется выполнить операцию «ИЛИ» над группой битов байта. Часто она используется для избирательной установки битов в байте.
Пример: ORL A,#0FH ; установка в «1»
ORL P1,#0C0H
Обобщенная мнемоника «ИСКЛЮЧАЮЩЕГО ИЛИ»:
Х Х Х Х
1 1 1 1
Х Х Х Х
Х
Х
1 1
XRL dest_byte, src_byte ; dest_byte := dest_byte src_byte
Варианты операндов те же. Эта команда эффективна, когда требуется выполнить операцию «ИСКЛЮЧАЮЩЕЕ ИЛИ» над группой битов байта. Часто она используется для избирательной инверсии битов в байте.
А
Пример: XRL A,#0FH
XRL P1,#0C1H
Х Х Х Х
Х Х Х Х
инверсия
Х Х Х Х
Х Х Х Х
Очистка и инверсия аккумулятора: CLR/CPL
Пример:
XRL A, ACC ; A := 0
MOV A, #0
CLR A ; A := 0
CPL ; A :=
— инверсия аккумулятора
Т.к. аккумулятор является центральным программным объектом, то для него зарезервированы две короткие команды, которые реализуют часто используемые с ним операции:
очистка и инверсия. Выполняются только с аккумулятором.
Циклические сдвиги: RL/RLC/RR/RRC
11
Рис. 2.2. Схемы циклических сдвигов
RL — сдвиг влево (в сторону ст. разряда), RR — сдвиг вправо (в сторону мл. разряда),
RLC и RRC — сдвиги с переносом. С помощью этих команд можно реализовывать разные типы сдвигов разных целочисленных переменных любой разрядности.
Типы сдвигов: циклический, логический, арифметический.
Логический сдвиг: влево — происходит сдвиг всех разрядов влево, но при этом старший
разряд теряется; вправо — аналогично, но сдвиг происходит вправо и теряется младший
разряд.
Арифметический сдвиг: влево — совпадает с логическим сдвигом влево; вправо — аналогично, но сдвиг вправо, но переполнения не будет, а знак сохраняется.
Пример:
1 000 1001 →
1 1 0 0 0 1 0 0 _ арифметический сдвиг
логический сдвиг
01000100
Пример. Логический сдвиг на один разряд влево 16-разрядной величины (R6СТ-R7МЛ):
XCH
CLR
RLC
XCH
A,R7 ; обмен содержимым
C ; сброс бита переноса
A ; сдвиг влево младшего байта
A,R7
; сдвиг влево
нельзя)
XCH A,R6
RLC A
XCH A,R6
старшего
байта
(здесь
бит
переноса
сбрасывать
Команда SWAP A (обмен содержимого аккумулятора) используется при манипуляции с
двоично-десятичными числами, а также может рассматриваться как циклический сдвиг
без переноса влево или вправо на четыре разряда.
7
4
3
12
2.4.4. Команды передачи управления. Подпрограммы и способы передачи параметров
К этой группе команд относятся команды вызова подпрограмм и возврата из подпрограмм, команды условного и безусловного ветвления, а также команда пустой операции
NOP.
Вызов подпрограмм и возврат из подпрограмм: LCALL/ACALL/RET/RETI
Подпрограмма — это поименованная часть программы, которая вызывается, выполняет
определенные действия и возвращает управление в точку вызова. Вызовы подпрограмм
могут быть вложенными, т.е. одна подпрограмма может вызывать другую подпрограмму,
а та, в свою очередь, еще другую. При этом, количество возможных вложенных подпрограмм определяется размером стека.
NameSubr:
(метка)
тело
подпрограммы
………………
RET
В команде вызова подпрограммы LCALL Subr (длинный вызов) содержится полный 16разрядный адрес подпрограммы. При выполнении этой команды PC := PC+3 – содержимое счетчика команд PC увеличивается на три и соответствует адресу следующей за
LCALL команды (адресу возврата). После сохранения PC в стеке ему присваивается значение Subr. Тем самым осуществляется переход на начало вызываемой подпрограммы.
Выход из подпрограммы (завершение подпрограммы) должен выполняться с помощью
команды RET, которая извлекает из стека адрес возврата и загружает его в PC. В результате осуществляется переход к следующей за LCALL команде или, как говорят, в «точку
возврата». Представленный ниже рисунок иллюстрирует выполнение команды LCALL.
Рис. 2.3. Схема выполнения подпрограммы Subr путем ее вызова командой LCALL и последующего возврата в основной цикл программы командой RET
Команда ACALL отличается от LCALL только разрядностью адреса и числом байтов, которых два. В команде ACALL адрес 11-разрядный; старшие три бита расположены в трех
младших битах первого байта (КОП) команды. Поэтому есть ограничение на размещение
кода подпрограммы и вызывающей ее команды ACALL: они должны находиться в одной
странице памяти размером 2048 байтов, что иллюстрирует рисунок, и внутри одного модуля файла.
13
Рис. 2.4. Схема выполнения подпрограммы Subr путем ее вызова командой ACALL
Допустимо применять обобщенный вызов подпрограммы путем выполнения команды
CALL. В этом случае происходит автоматический выбор команды ACALL или LCALL.
Команда RETI должна завершать подпрограммы обработки прерываний. Дополнительно
к действиям команды RET эта команда восстанавливает логику прерываний. Команда
RETI разрешает прерывания того же уровня приоритета, что и приоритет обработанного
прерывания.
Способы передачи параметров подпрограмм:
1) через регистры общего назначения R0-R7, DPTR, A, B — это самый быстрый способ
передачи параметров и наиболее распространенный, при этом через регистр можно передавать как значение, так и адрес.
2) через заданную область памяти. В этом случае параметры должны быть сформированы
в памяти вызывающей подпрограммой, базовый адрес должен быть определен вызывающей подпрограммой. Если используется общая область памяти, то теряется возможность
повторного входа в подпрограмму. Недостатком данного способа является большой расход памяти и низкое быстродействие.
BaseAddr:
заданная здесь предварительно
формиру тся
область
памяти вызыва ие параметры
MOV DPTR, #BaseAddr ; передать базовый адрес
LCALL Subr ; вызов
3) через программную память непосредственно. Для данного случая все параметры должны быть неизменяемыми, т.к. все программы располагаются в ПЗУ. Базовый адрес параметров находится на вершине стека после вызова подпрограммы стандартным способом.
LCALL Subr
DB Param1, Param2, …
……………………….
; далее выход из подпрограммы
Subr:
загрузка в
14
CLR A
MOVC A, @A+DPTR ; считан Param1
……………………………………….
CLR A
INC A ; не забывать увеличивать DPTR на 1
MOVC A, @A+DPTR
……………………………………………
выход из
подпрограммы
4) через стек.
загрузка
в стек
……………………….
LCALL Subr
Subr:
MOV R0, SP ;
DEC R0
DEC R0
MOV A, @R0 ; A := Param2
……………………………..
MOV R1, SP
DEC R1
MOV A, @R1
MOV @R0, A ; в стек поместился по требуемому адресу младший
байт возврата
INC R0
INC R1
MOV A, @R1
MOV @R0, A
MOV SP, R0 ; очистка стека — правильно провести указатель
стека в исходное состояние
RET ; выход из подпрограммы
Главными недостатками данного способа являются его неэффективность и длительность
выполнения процедур входа в подпрограмму и выхода из нее. Наиболее приемлемыми для
микроконтроллеров 51-ого семейства являются два первых способа передачи параметров
подпрограмм.
15
Безусловные переходы: LJMP/AJMP/SJMP
В команде LJMP Addr16 содержится полный 16-разрядный адрес перехода. При выполнении этой команды PC := Addr16, что приводит к переходу по указанному адресу, при
этом возможен переход на внешние адреса. В команде AJMP адрес 11-разрядный, как в
команде ACALL. Поэтому сама команда AJMP и адрес (метка), на который она ссылается, должны находиться в одной странице памяти размером 2048 байтов (одном модуле).
В коротком переходе SJMP rel (2 байта) адрес перехода указывается смещением относительно адреса команды, следующей за команSJMP M1
-128
дой SJMP, при этом подпрограмма может на- PC
ходиться в разных модулях. Смещение пред- PC+2 Следующая команда +127
ставляется вторым байтом команды в дополнительном коде (знаковое целое). Этот переход позволяет передать управление в пределах 128 +127 байт относительно адреса следующей команды. На языке ассемблера Вы пишете обычную символическую метку, а программа-ассемблер вычислит необходимое
смещение при переводе этой команды в двоичный код. Можно поручить ассемблеру выбирать оптимальную (наиболее короткую) команду безусловного перехода, если воспользоваться обобщенной мнемоникой JMP.
↓
SJMP M1
Косвенный переход: JMP @A+DPTR
После выполнения этой команды ни аккумулятор, ни DPTR, ни флаги не изменяют своего
значения. Эта команда позволяет организовать переход по адресу, вычисляемому в процессе выполнения программы (т.е. который указывает сумма). Обычно она применяется
для реализации ветвления программы из одной точки по нескольким направлениям.
Пример. Реализация оператора выбора:
TBL_JMP:
MOV
ADD
JMP
DPTR,#TBL_JMP
A,ACC
@A+DPTR
AJMP
AJMP
AJMP
.
.
AJMP
LB0
LB1
LB2
; ACC содержит целочисленну
; в диапазоне от 0 до -127
переменну
LBn
Условные переходы: JZ/JNZ/CJNE/DJNZ
Во всех этих командах используется только короткий относительный переход. Команды
JZ и JNZ тестируют текущее содержимое аккумулятора соответственно на равенство и
неравенство нулю. Если тестируемое условие истинно, управление передается на метку,
указанную в команде; иначе – на следующую команду.
Команды сравнения имеют следующую обобщенную запись: CJNE Op1, Op2, rel. При
выполнении этой команды сравниваются два операнда Op1 и Op2. Если они не равны,
управление передается по адресу, которому соответствует смещение rel; иначе – на следующую команду. Эта команда воздействует на бит переноса CY: если Op1 < Op2,
CY = 1; иначе (Op1 >= Op2) CY = 0. Это позволяет использовать данные команды для
сравнения чисел (как однобайтовых, так и многобайтовых), т.е. можно реализовать операции: «=», «», «>», «<», «>=», «<=».
16
Пример. Сравнение A < B:
CJNE
JC
A, B, $+3
; $ - теку ее значение PC, $+3 – адрес
A_LT_B
; следу ей команды
; A < B, то переход по ссылке
; A >= B
Команда вида DJNZ Cnt_Byte, rel уменьшает на 1 операнд Cnt_Byte, а затем проверяет
его на 0: если значение Cnt_Byte не равно нулю, управление передается на метку; иначе –
на следующую команду (как выход из цикла, см. далее). Команды этого вида удобны для
реализации циклов по следующей схеме:
Cnt_Byte := C0
; Инициализация счетчика цикла
Loop: Тело цикла
DJNZ Cnt_Byte,Loop
; Модификация счетчика цикла и проверка его на ноль
; Если требуется организовать 256 циклов, то загружать в счетчик надо 0
Пустая операция: NOP
Эта команда ни на что не влияет. Применяется обычно для организации небольших задержек.
2.4.5. Команды битового процессора
В рассматриваемой группе команд операнды однобитовые, допускающие только прямую
адресацию. В качестве таких операндов могут выступать битовые переменные (определенные в сегменте типа BIT) и биты битадресуемых РСФ. Бит переноса CY играет роль
аккумулятора для бинарных битовых операций. Поскольку CY занимает центральное место, то для него предусмотрены отдельные эффективные команды, выполняющие часто
встречающиеся операции с его значением.
Сброс, установка и инверсия битов: CLR/SETB/CPL
Предусмотрены отдельные команды для сброса (CLR C), установки (SETB C) и инверсии
(CPL C) бита переноса. Отличительная их особенность – размер один байт и время выполнения один машинный цикл. Такие же действия можно выполнить с любым адресуемым битом: CLR bit (сброс бита), SETB bit (установка бита), CPL bit (инверсия бита).
Эти команды выполняются за один машинный цикл, но занимают в памяти 2 байта; второй байт требуется для указания адреса бита. Бит EA — разрешает/запрещает прерывания.
Способы записи битов на ассемблере:
CLR bit
имя переменной (битовой) в сегменте класса BIT
имя бита битадресуемого РСФ
ACC.имя_бит
а
имя_РСФ.имя_бит
а
Битовые операции «И», «ИЛИ»: ANL/ORL
имя_бита_РСФ
Здесь одним из операндов и операндом назначения по умолчанию является бит переноса
CY. Имеется две формы записи этих команд, отличающиеся наличием правой косой чер17
ты перед вторым битовым операндом. Эта черта означает, что в операции будет участвовать инверсное значение бита. Команды этого типа занимают в памяти 2 байта и выполняются за 2 машинных цикла.
Пример:
SETB C
; установка переноса в «1»
SETB bit
CPL C
; C :=
CPL bit
; bit :=
ANL C, bit
; C := C ^ bit
ANL C, /bit
; C := C ^
ORL
; - «ИЛИ»
-//-
- «И»
- «И»
Пересылка битов : MOV
Пересылки выполняются только через бит переноса CY. Команда MOV C, bit копирует
значение bit в бит переноса, команда MOV bit, C выполняет обратное копирование. Для
реализации пересылки между двумя произвольными битами (bit1 := bit2) требуется последовательное выполнение этих двух команд:
MOV
MOV
C, bit1
bit2, C
Условные переходы (тестирование битов): JC/JNC/JB/JNB/JBC
Эти команды позволяют осуществлять ветвление по следующим условиям: перенос равен
«1» (JC), тогда переход на метку; перенос равен нулю (JNC), то переход на метку; адресуемый бит равен «1» (JB/JBC), то переход на метку; адресуемый бит равен нулю (JNB),
то переход на метку. Здесь тоже используется только короткий относительный способ адресации перехода при выполнении условия, тестируемого в команде. Если условие не выполняется, управление, как всегда, передается следующей команде.
Особый интерес представляет команда JBC, которая проверяет указанный бит на «1». Если бит равен «1»,
он сбрасывается, а управление передается на метку, указанную в команде. Эта команда может быть полезна,
когда требуется не разрывать тестирование бита и его сброс в случае равенства бита «1». Такая ситуация
встречается в коммуникационных процедурах.
2.5. Выражения и операторы (вычисления во время трансляции)
Операнд может быть:
числовой константой,
символическим именем,
строкой,
выражением.
Операторы (операции) используются для комбинирования (сочетания, объединения, соединения) и сравнения операндов. Операторы не являются инструкциями (командами)
языка ассемблера и не генерируют код. Операторы представляют действия (числовые
операции), которые выполняются во время ассемблирования.
Выражение — это комбинация чисел, строк, имен и операторов, которое, в конце концов, выражается (приводится) для A51 как 16-битовое число (может быть знаковое). Т.к.
18
выражения вычисляются во время ассемблирования, то они могут использоваться для
вычисления значений, которые иначе заранее трудно определить.
Пример: MOV A, #3+5 ; простейшее выражение – число
2.5.1. Целые числа
Числа могут быть представлены в шестнадцатиричной, десятичной, восьмеричной и двоичной системах счисления. Основание системы счисления указывает последний символ
(суффикс) числа. По умолчанию предполагается десятичная система счисления. Следующая таблица содержит базовые типы, их суффиксы и некоторые примеры.
Основание системы
счисления
Шестнадцатеричная
Десятичная
Восьмиричная
Двоичная
Суффикс
Допустимые символы
Примеры
H, h
D, d
O, o, Q, q
B, b
0 – 9, A – F, a – f
0–9
0–7
0, 1
12H, 0FFH, 0Fh
12, 12D, 99, 100
17Q, 123Q
10011100B
Первым символом числа должна быть цифра 0–9. Когда шестнадцатеричное число начинается с буквы, то оно должно иметь приставку 0. Ассемблер Ax51 поддерживает также
запись HEX-чисел в стиле языка Си, например 0х123.
Знак «$» может быть использован в числах для улучшения читаемости. Но этот знак не
может быть первым или последним символом в записи числа. Этот знак игнорируется ассемблером и не влияет на значение числа. Например:
2.5.2. Символы
Ассемблер Ax51 дает вам возможность использовать ASCII-символы в выражениях, чтобы генерировать числовое значение. До 2-х символов, заключенных в апострофы (одиночные кавычки), можно использовать в выражениях. Например:
Символ Числовое соответствие (представление)
Использование в программе
MOV a, ’A’ ; ACC := 41h
‘A’
0041h
MOV a, ’9’ ; ACC := 39h
‘AB’
4142h
CLR C
‘a’
0061h
SUBB A, ’0’ ; ACC := 9
‘’
‘abcd’
Ошибка
Символы могут использоваться в программе как операнд непосредственных данных.
2.5.3. Символьные строки
Символьные строки обычно используются в комбинации (вместе) с директивой DB для
определения сообщений (константных), используемых в программе. Символьная строка
— это последовательность символов, заключенная в апострофы. В директиве DB строки
могут смешиваться с числами.
Например:
Mes:
Mes:
DB ‘Error’
DB ‘Error’, 0
; Error: 45h,72h,72h,6fh,72h
; Строка в стиле Си
Если требуется записать в строке символ апострофа, то последний удваивается.
19
2.5.4. Счетчик адресов (Location Counter)
Ассемблер обслуживает свою внутреннюю переменную СА (счетчик адреса) для каждого
сегмента. СА содержит смещение (адрес) инструкции или данных и увеличивается после
каждой строки на число байтов данных или кода в этой строке. СА инициализируется 0
для каждого сегмента. Однако его значение можно изменить с помощью директивы ORG.
Знак «$» возвращает текущее значение счетчика. Этот оператор позволяет использовать
СА в выражениях.
Примеры:
/* Пусть адрес метки Str равен 100, тогда длина строки составляет 10 символов, а адрес конца строки будет иметь значение 109.
Символ конца строки (ограничитель) тогда будет иметь адрес 110.
*/
Str:
StrLen
db
equ
‘Это пример’, 0
$ - Str – 1 ; длина строки = 111 - 100 - 1
Можно также использовать символ «$» в инструкциях (везде, где допустимо выражение).
sjmp & ; Программная «ловушка» (бесконечный цикл)
cjne
jc
a, #3, $+3
LT
→
; ACC < 3
↓
; ACC >= 3
2.5.5. Операторы (операции)
Ассемблер A51 предоставляет несколько классов операторов, которые позволяют вам
сравнивать и комбинировать (сочетать) операнды и выражения. Эти операторы представлены ниже в следующей таблице.
Арифметические операторы
Арифметические операторы выполняют такие функции как сложение, вычитание, умножение и деление. Эти операторы требуют один или два операнда в зависимости от операции (выполняемой функции). Результат всегда 16-битовое значение. Переполнение или
заем не обнаруживаются. Деление на 0 обнаруживается и приводит к ассемблерной ошибке. В следующей таблице представлен список арифметических операторов и их краткое
описание.
Пример:
?DT?file
segment data
RSEG ?DT?file
X:
DS 4 ; - размер 4-х байт
…………………
; программный сегмент
CLR A
MOV X, A
; по адресу А
MOV X+1, A ; А – адрес следу
ей ячейки
MOV X+2, A
MOV X+3, A
20
Операторы
Оператор
+
+
*
/
MOD
( )
NOT
SHR
SHL
AND
OR
XOR
GTE
>=
LTE
<=
NE
<>
EQ
=
LT
<
GT
>
LOW
HIGH
Синтаксис
Описание
Арифметические операторы
+ выражение
Унарный плюс
- выражение
Унарный минус
выражение + выражение
Сложение
выражение - выражение
Вычитание
выражение* выражение
Умножение
выражение / выражение
Целочисленное деление
выражение MOD выражение Остаток
(выражение)
Устанавливают порядок выполнения операций
Двоичные операторы
NOT выражение
Побитовая инверсия
выражение SHR число сдви- Логический сдвиг вправо
гов
выражение SHL число сдви- Логический сдвиг влево
гов
выражение AND выражение
Побитовая операция «И»
выражение OR выражение
Побитовая операция «ИЛИ»
XOR выражение
Побитовая операция «ИСКЛЮЧАЮЩЕЕ
ИЛИ»
Операторы отношения (сравнения)
выражение1 >= выражение2
Истина, если выражение1 больше или равно
выражение2; иначе – ложь
выражение1 <= выражение2
Истина, если выражение1 меньше или равно
выражение2; иначе – ложь
выражение1 <> выражение2
Истина, если выражение1 не равно выражение2; иначе – ложь
выражение1 = выражение2
Истина, если выражение1 равно выражение2; иначе – ложь
выражение1 < выражение2
Истина, если выражение1 меньше выражение2; иначе – ложь
выражение1 > выражение2
Истина, если выражение1 больше выражение2; иначе – ложь
Прочие операторы
LOW выражение
Младший байт выражения
HIGH выражение
Старший байт выражения
Двоичные операции (операторы)
Двоичные операторы используются для инверсии, сдвига и выполнения побитовых операций над двоичными значениями их операндов. Следующая таблица содержит список двоичных операторов и их краткое описание.
Операторы отношения
Эти операторы сравнивают два операнда. Результат сравнения – TRUE или FALSE. Результат FALSE имеет значение 0000h. TRUE-результат имеет ненулевое значение. Следующая таблица содержит список операторов сравнения и их краткое описание.
21
Прочие операторы
Здесь представлены операторы, не вошедшие в предшествующие категории. Это операторы LOW и HIGH, возвращающие соответственно младший и старший байт выражения.
Пример:
X:
DS 2
X_0 EQU 1000
; программный сегмент
MOV X, #HIGH X_0
MOV X+1, #LOW X_0
Приоритет операторов
Все операторы выполняются в точном, строго определенном порядке. Порядок вычислений (evaluation) имеет отношение к приоритету операторов. Последний требуется для того, чтобы определить какие операторы выполняются первыми в выражении. Ниже следующая таблица содержит список операторов в порядке их выполнения. Операторы первого уровня выполняются первыми. Операторы с одинаковым приоритетом выполняются
слева направо.
Приоритет операторов
Уровень приоритета
1
2
3
4
5
6
7
8
Операторы
()
NOT, HIGH, LOW
+ (унарный), - (унарный)
*, /, MOD
+, SHR, SHL
AND, OR, XOR
>=, GTE, <=, LTE, =, EQ, <>, NE, <, LT, >, GT
2.5.6. Выражения
Выражения — это комбинация операндов и операторов, которая может быть вычислена
ассемблером. Операнд без операторов – простейшая форма выражения. Выражение может
быть использовано во многих местах, где требуется операнд. Выражения имеют ряд атрибутов, описанных ниже.
Классы выражений
Класс выражения назначается на основе используемых в них операндов. Следующие
классы применимы к выражениям:
N NUMBER — класс выражения типа число number (безклассвое число);
C ADDR — адрес имени в памяти типа CODE;
D ADDR — адрес имени в памяти класса DATA;
I ADDR — -//- IDATA
X ADDR — -//- XDATA
B ADDR — адрес имени в памяти типа BIT.
Часто выражениям назначается класс NUMBER, т.к. они состоят только из числовых операндов, например MOV A, #3*2. При этом, значению символического адреса автоматически присваивается класс сегмента, где определен адрес. Когда значение имеет класс используются следующие правила:
1) результат унарный операции имеет тот же класс, что и операнд;
22
2) результат всех бинарных операций за исключением сложения и вычитания будет
иметь класс NUMBER;
3) если только один из операндов операции сложения или вычитания имеет класс,
то результат будет иметь тот же класс;
4) если оба операнда имеют класс, то результат будет иметь класс NUMBER.
Это означает, что значение с классом ± число дает значение с классом.
Абсолютные выражения (константы) — всегда завершают свои вычисления до конца.
Перемещаемые выражения
Перемещаемые выражения так называются потому, что они содержат ссылку на перемещаемое или внешнее символическое имя. Выражения этих типов могут быть вычислены
ассемблером только частично, т.к. ассемблер не знает конечного адреса перемещаемых
сегментов. Завершает вычисления линкер – редактор связей.
Перемещаемое выражение обычно содержит только перемещаемое символическое имя,
однако оно может также содержать и другие операнды и операторы. Перемещаемое символическое имя может быть модифицировано прибавлением или вычитанием константы.
Имеется два базовых типа перемещаемых выражений: простые перемещаемые выражения и расширенные перемещаемые выражения.
Простые перемещаемые выражения
Простые перемещаемые выражения содержат имена, которые определены в перемещаемом сегменте. Это имена меток, подпрограмм, внешних ссылок. Но имена сегментов и
внешние имена не допустимы в простых перемещаемых выражениях.
Простое перемещаемое выражение может быть использовано в 4-х контекстах (ситуациях):
1) как операнд директивы ORG;
2) как операнд в директивах назначения именам числовых значений (т.е. EQU, SET);
3) как операнд в директиве инициализации кодовой памяти (DB, DW);
4) как операнд машинной инструкции (команды).
Примеры:
REL1 + ABS1 * 10 ; здесь REL1 – переме аемое имя (метка), ABS1 –
;
REL2 ± ABS1
константа, а «ABS1*10» – сложное выражение
; здесь ABS1 – абсол тное выражение
REL1 + (REL2 – REL3) ; REL2 и REL3 – переме аемые имена в одном
;
сегменте
; далее показаны неверные (недопустимые) приемы
(REL1 + ABS1) * 10
EXT1 - ABS1
; здесь EXT1 – внешнее имя
REL1 + REL2
; REL1 и REL2 – два переме аемых выражения
23
Расширенные перемещаемые выражения
К этим выражениям в основном применимы те же правила, что и к простым перемещаемым выражениям. Имена сегментов и внешние имена допустимы в расширенных перемещаемых выражениях. Расширенные перемещаемые выражения могут быть использованы
только в качестве операндов операторов, генерирующих код (как операнд машинной инструкции, и как операнд в директиве инициализации кодовой памяти DB и DW).
Примеры:
допустимые
REL1 + ABS*10
EXT1 ± ABS1
LOW(REL1+ABS1)
WORD2 (SEG1)
недопустимые
(SEG1+ABS1)*10
EXT1 - REL1
LOW(REL1) + ABS1
/* Вход в подпрограмму Subr и начало выполнения команды, име ей
адрес
на
три
пункта
больше,
чем
адрес
точки
входа
в
подпрограмму, т.е. по сути происходит «обход» или пропуск двух
команд в начале подпрограммы */
MOV SP, #STACK-1 ; здесь STACK – имя сегмента
LCALL Subr + 3 ; здесь Subr – имя внешней подпрограммы
2.6. Директивы ассемблера A51 фирмы KEIL
2.6.1. Управление сегментированием памяти
Сегмент — блок программной памяти или памяти данных, которую создает ассемблер из
кода или данных исходного (ассемблерного) файла. Семейство микроконтроллеров семейства 8051 имеет несколько специфических областей (пространств) памяти. Вы
используете сегменты для размещения программного кода, констант и переменных в этих
областях.
Счетчик адреса
A51 для каждого сегмента обслуживает счетчик адреса (СА). Последний есть указатель в
адресном пространстве активного сегмента. Он представляет смещение для
перемещаемых сегментов или действительный адрес для абсолютных сегментов. При
первой активизации сегмента счетчик адреса устанавливается в 0. После каждой
инструкции (команды) СА изменяется на число байтов, соответствующее инструкции.
Директивы инициализации и резервирования памяти также изменяют значение СА.
Директива ORG устанавливает новое значение СА. Если вы изменили активный сегмент
и позже вернулись к этому сегменту, СА восстановит свое предыдущее значение. Каждый
раз, когда ассемблер встречает метку, он назначает метке текущее значение СА и тип
текущего сегмента. Знак $ указывает значение СА в активном сегменте. Ниже
описываются различные типы сегментов.
Перемещаемые сегменты
Перемещаемые сегменты имеют имя, класс и другие атрибуты. Перемещаемые сегменты с
одинаковым именем, но из разных объектных модулей, рассматриваются как части одного
и того же сегмента и называются частичными (неполными) сегментами. Эти сегменты
объединяются во время компоновки редактором связей. Перемещаемые сегменты
создаются директивой SEGMENT. После определения имени перемещаемого сегмента,
вы можете выбрать сегмент, используя директиву RSEG. Выбранный сегмент становится
24
активным и остается таковым, пока сегмент не будет изменен очередной директивой
RSEG или директивой определения абсолютного сегмента.
Обычно ассемблерные подпрограммы помещают в перемещаемые сегменты. Если вы сопрягаете ваши
ассемблерные подпрограммы с Си-программами, то эти подпрограммы должны находиться в отдельных
перемещаемых сегментах, а имена сегментов должны соответствовать принятым в Cx51 стандартам.
Сегмент стека
Приложение для 8051 должно установить указатель стека на область памяти, которая не
будет использована другими переменными. Для классических производных 8051 должен
быть определен сегмент стека, и для него должно быть зарезервировано пространство, как
представлено ниже.
STACK
SEGMENT
RSEG
DS
IDATA
STACK
10H
Затем вы должны инициализировать указатель стека в начале вашей програмы (абсолютный сегмент класса CODE следует начинать с нулевого адреса).
CSEG
AT 0
JMP STARTUP
STARTUP:
MOV SP, #STACK-1
Абсолютные сегменты
Абсолютные сегменты размещаются в фиксированных ячейках памяти. Абсолютные сегменты создаются директивами: CSEG, DSEG, XSEG, ISEG, BSEG. Эти директивы разрешают вам размещать код и данные или резервировать пространство памяти в фиксированных ячейках памяти. Вы используете абсолютные сегменты, когда вам нужен доступ к
фиксированной области памяти или когда вы хотите поместить программный код или
константы-данные по фиксированному адресу памяти.
Сегмент по умолчанию
По умолчанию ассемблер полагает, что выбран сегмент CODE, и устанавливает СА в
0000H, когда он начинает обрабатывать исходный ассемблерный модуль. Это позволяет
вам создавать программы без указания директив сегментирования.
Директива SEGMENT
Директива SEGMENT используется для объявления перемещаемого сегмента. При этом
могут быть указаны типы перемещения и выравнивания сегмента. Формат директивы:
SegName
SEGMENT class reloctype alloctype
где
SegName — имя, назначенное сегменту. Это имя указывается в рассматриваемой ниже
директиве RSEG. Имя сегмента может использоваться в выражениях для представления
базового или стартового адреса объединенного сегмента, вычисленного редактором связей (линкер).
class — класс памяти. Имя сегмента в каждом модуле должно быть уникальным. Однако редактор связей (линкер) объединяет сегменты одинакового типа. Это правило также
распространяется на сегменты, объявленные в других модулях. Класс используется линкером для доступа ко всем сегментам, принадлежащим данному классу. Базовые классы
перечислены ниже:
25
Базовый класс
Описание
BIT
Битовая область внутреннего ОЗУ (адреса 20H...2FH)
CODE
Область программной памяти (ПЗУ)
DATA
Прямоадресуемая область внутреннего ОЗУ (адреса 0…7FH и РСФ: 80H...FFH)
IDATA
Косвенно адресуемая область внутреннего ОЗУ (адреса 0…FFH)
XDATA
Область внешнего ОЗУ
reloctype — тип перемещения для сегмента. Он определяет дополнительные операции
перемещения, которые могут быть исполнены линкером. Следующая таблица содержит
список допустимых типов перемещения:
Тип перемещения
BITADDRESSABLE
INBLOCK
INPAGE
OVERLAYABLE
Описание
Специфицирует сегмент, который будет размещен в области внутреннего ОЗУ с побитовой адресацией (20H...2FH в области DATA). Т.е. в области BIT заводится байтовая переменная, и тогда можно обращаться к каждому биту переменной. Этот тип
перемещения допустим только для сегментов класса DATA, размер которых не превышает 16 байтов.
Устанавливает сегмент, который должен включаться в блок, размером 2048 байтов.
Этот тип перемещения допустим только для сегментов с классом CODE.
Специфицирует сегмент, который должен содержаться в странице памяти, размером
256 байтов.
Указывает, что сегмент может совместно использовать память с другими сегментами.
Сегменты, объявленные с этим типом перемещения, могут перекрываться другими
сегментами, также объявленными с типом перемещения OVERLAYABLE. При использовании этого типа перемещения имя сегмента должно объявляться в соответствии с правилами назначения имен в C251, CX51, C51 или PL/M-51.
alloctype — тип выравнивания сегмента. Определяет операции перемещения, которые
могут быть исполнены линкером. Ассемблер A51 допускает только один тип выравнивания – PAGE, который указывает, что начальный адрес сегмента должен быть
на границе 256-байтовой страницы памяти.
BIT
банки
регистров
Примеры:
DT BT ; объявление битового сегмента (BIT) в сегменте данных
; (класс DATA)
?PR? BA ; объявление переменной типа bitaddressable в
; программном сегменте (класс CODE)
?BA?file SEGMENT data bitaddressable ; объявление сегмента
Директива RSEG
Директива RSEG выбирает ранее объявленный директивой SEGMENT перемещаемый
сегмент. Директива RSEG имеет следующий формат:
RSEG SegName
где SegName — имя сегмента, ранее объявленного директивой SEGMENT.
Примеры:
RSEG ?BA?file
V1: DS 1
; резервирует число байтов переменной
MOV V1, #3 ; работа с целым байтом
CLR 1.1 ; очистка бита
26
Директивы управления абсолютными сегментами
Эти директивы используют следующий формат:
BSEG
CSEG
DSEG
ISEG
XSEG
AT
AT
AT
AT
AT
address
address
address
address
address
определяет абсолютный сегмент класса BIT
определяет абсолютный сегмент класса CODE
определяет абсолютный сегмент класса DATA
определяет абсолютный сегмент класса IDATA
определяет абсолютный сегмент класса XDATA
где address — необязательный абсолютный базовый адрес, с которого начинается сегмент. Параметр address не может содержать ссылок вперед и должен быть выражением,
которое результатом вычисления имеет допустимое значение адреса.
2.6.2. Определение символов (назначение именам числовых значений)
Директивы определения символов предоставляют вам возможность создавать символы,
которые могут использоваться для представления регистров, чисел и адресов. Символы,
определяемые этими директивами не должны предварительно определяться и не должны
переопределяться. Только директива SET является исключением из этого правила.
Директивы EQU и SET
Директивы EQU и SET присваивают символическому имени SymName целочисленное
значение или символ регистра. Символы, определяемые EQU, не должны быть предварительно определены и не допускают переопределения. Директива SET допускает переопределение символов. Формат директив следующий:
SymName
SymName
SymName
SymName
EQU
EQU
SET
SET
expression
register
expression
register
где
expression — целочисленное выражение (константное), не содержащее ссылок вперед,
или простое перемещаемое выражение. Последнее содержит символы, определенные в
перемещаемом сегменте; имена сегментов и внешние символы недопустимы в простых
перемещаемых выражениях.
register — любое имя одного из регистров: A, B, R0R7, ...
Символы, определенные директивами EQU и SET, могут использоваться везде: в операндах, выражениях, адресах. Символы, определенные как регистры, могут использоваться
везде, где допустим регистр. С помощью директивы EQU нельзя переопределять константны, а с помощью SET можно.
Примеры:
MOV A, #SymName
Cnt EQU R7
………………………
DJNZ Cnt, Loop
2.6.3. Директивы назначения адресов
Директивы: BIT, CODE, DATA, IDATA, XDATA — присваивают значение адреса
указанному символу SymName. Символы, определенные этими директивами, не могут
быть изменены или переопределены. Формат директив следующий:
27
SymName
BIT
bit_address
; определяет BIT-символ
SymName
CODE
code_address
; определяет CODE-символ
SymName
DATA
data_address
; определяет DATA-символ
SymName
IDATA
idata_address ; определяет IDATA-символ
SymName
XDATA
xdata_address ; определяет XDATA-символ
где
bit_address — адрес бита в области внутреннего ОЗУ (20H...2FH) с побитовой
адресацией или адрес бита РСФ с побитовой адресацией.
code_address — адрес кодовой памяти в диапазоне 0000H...0FFFFH.
data_address — адрес прямоадресуемой ячейки внутреннего ОЗУ в диапазоне 0...127
или адрес РСФ в диапазоне 128…255.
idata_address — адрес косвенно адресуемой ячейки внутреннего ОЗУ в диапазоне
0...255.
xdata_address — адрес ячейки внешней памяти данных в диапазоне 0...65535.
Кроме этих директив, имеются еще директивы аналогичного назначения sfr, sfr16, sbit,
которые полностью совместимы с компилятором Cx51. В результате предоставляется
возможность использовать один общий файл определения РСФ как для ассемблера Ax51,
так и для компилятора Cx51.
Пример. Назначение переменной в фиксированный адрес:
sfr sfr_sumbol = address_sfr (0x50-0xff)
sbit sfr_bit_symbol = bit_address
; 16 разрядов состоит из двух байт (к DPTR это не применимо)
младший
Addr
адрес мл. байта
L
H
8
8
старший
16 разрядов
sfr16 Adc_date = Addr
Addr+1
; Addr (L)
2.6.4. Директивы инициализация кодовой памяти
Директивы инициализации памяти используются для определения констант в кодовой памяти (ПЗУ). При этом инициализация памяти может выполняться байтами (директива DB)
или словами (директива DW). Формат директив следующий:
Label:
Label:
где
DB
DW
expression, expression ...
expression, expression ...
H
L
Addr
Addr+1
Label — символ, который задает адрес инициализируемой памяти.
expression — байтовое значение для DB и шестнадцатиразрядное значение для DW.
Каждое expression может быть символом, строкой символов или числовым значением,
при этом выражение может быть любого типа. Директивы DB и DW могут быть заданы
только в сегменте класса CODE, в противном случае будет выдано сообщение об ошибке.
28
2.6.5. Директивы резервирования памяти
Эти директивы используются для резервирования памяти под переменные. Начало
резервирования соответствует текущему значению счетчика адреса в текущем активном
сегменте.
DBIT
Директива DBIT резервирует пространство в битовом сегменте. Директива имеет следующий формат:
Label:
DBIT expression
где
Label — символ, задающий адрес резервируемой памяти. Этот символ имеет класс BIT.
expression — число резервируемых битов. Выражение expression не может содержать ссылки вперед, перемещаемые или внешние символы.
Директива DBIT резервирует пространство в битовом сегменте, начиная с текущего адреса. Счетчик адреса для битового сегмента увеличивается на значение expression.
DS
Директива DS резервирует заданное число байтов в сегментах памяти DATA, XDATA,
IDATA. Директива имеет следующий формат:
Label:
DS
expression
где
Label — символ, задающий адрес резервируемой памяти. Символ Label — нетипизированное целочисленное значение – принимает значение текущего адреса и класс памяти
активного сегмента.
expression — число резервируемых байтов. Выражение expression не может содержать ссылки вперед, перемещаемые или внешние символы.
Директива DS резервирует пространство в текущем сегменте, начиная с текущего адреса.
Затем текущий адрес увеличивается на значение expression.
Примеры:
X1
X1:
DS 4
X2:
DS 1 ; addr X2 = addr X1 + 4
X3:
DS 2 ; addr X3 = addr X2 + 1 = addr X1 + 5
X1+1
X1+2
X1+3
MOV R0, #X1 ; косвенная адресация – в регистр R0 значение X1
2.6.6. Директивы межмодульной связи
Эти директивы делают возможным взаимодействие между независимо ассемблируемыми
модулями, разрешая межмодульные связи и именование модулей.
PUBLIC
Эта директива указывает список символов, которые могут быть использованы в других
объектных модулях. Директива PUBLIC имеет следующий формат:
PUBLIC
symbol, symbol ...
где symbol — символическое имя, определенное где-либо в исходном файле, исключая
имена регистров и сегментов. Допускаются ссылки вперед.
29
EXTRN
Эта директива указывает список символов, которые объявлены в других модулях. Директива EXTRN имеет следующий формат:
EXTRN class (symbol, symbol ...), class (symbol, symbol ...),...
где
class — класс памяти, где был определен символ; класс может принимать одно из значений: BIT, CODE, DATA, IDATA, XDATA или NUMBER (специфицирует символ без
класса);
symbol — внешнее символическое имя.
Редактор связей во время компоновки определяет значения всех внешних символов и проверяет соответствие их классов (заданных директивой EXTRN и PUBLIC). Символы с
классом NUMBER соответствуют любому классу памяти.
NAME
Директива NAME задает имя объектного модуля. Имя объектного файла может не совпадать с именем объектного модуля, имя которого встраивается в объектный файл. По
умолчанию, когда директива NAME не присутствует в исходном файле, имя модуля будет
совпадать с именем исходного файла без расширения. В исходном файле директива
NAME может быть указана только один раз. Формат директивы следующий:
NAME
modulename
где modulename — имя объектного модуля, которое может содержать до 40 символов.
2.6.7. Директивы управления адресом
Следующие директивы предоставляют управление счетчиком адреса или абсолютными
именами регистров банка.
ORG
Директива ORG используется для изменения значения счетчика адреса активного сегмента (устанавливает новый начальный адрес для последующих операторов). Формат директивы следующий:
ORG expression
где expression – абсолютное или простое перемещаемое выражение без ссылок вперед.
Допускается использовать только абсолютные адреса или символические значения текущего сегмента.
Когда встретится эта директива, ассемблер вычислит значение выражения и изменит
счетчик адреса (СА) текущего сегмента. Если директива ORG находится в абсолютном
сегменте, СА присваивается значение абсолютного адреса. Если директива ORG находится в перемещаемом сегменте, СА присваивается смещение, заданное выражением.
Замечание. Рассматриваемый ассемблер является многопроходным. При первом проходе собираются символы, и определяется длина каждой инструкции. Во втором проходе определяются значения ссылок вперед,
и производится объектный код. Поэтому выражение, используемое в директиве ORG, не может содержать
ссылок вперед.
USING
Директива USING указывает регистровый банк, который будет использован при кодировании регистров AR0AR7, но не переключает его. Формат директивы следующий:
30
USING
expression
где expression — номер регистрового банка в диапазоне 03.
Эта директива не генерирует какой-либо код, изменяющий номер регистрового банка. Регистровый банк, выбранный директивой USING, отмечается в объектном файле. В результате компоновщиком (редактором связей) резервируется память, требуемая этим регистровым банком.
Значение AR0AR7 вычисляется как абсолютный адрес R0R7 в регистровом банке, указанном директивой USING. Некоторые инструкции 8051 (например, PUSH/POP) допускают использование только абсолютных адресов регистров. По умолчанию регистровый
банк 0 назначен символам AR0AR7.
Примеры:
USING 1
PUSH AR0 ; для этих имен банк №1
2.6.8. Прочие директивы
END
Директива END оповещает о конце ассемблерного модуля. Любой текст в ассемблерном
файле, оказавшийся после директивы END, игнорируется. Эта директива требуется в каждом ассемблерном файле; в противном случае будет генерироваться предупреждение.
__ERROR__
Директива __ERROR__ генерирует стандартные сообщения об ошибках, которые составляются в том же стиле, что и обычные ошибки ассемблера. Директива имеет следующий
формат:
__ERROR__
text
где text — сообщение об ошибке (в двойных кавычках), которое должно отражаться в
листинговом файле. Этот же текст выводится на дисплей, если использована управляющая директива ERRORPRINT.
2.7. МАКРОКОМАНДЫ АССЕМБЛЕРА
Макрокоманда (макрос) — имя, назначаемое вами одному или нескольким ассемблерным
операторам. Для наибольшей гибкости макроассемблер предоставляет три различных
макроязыка:
Стандартные ассемблерные макросы.
Си-макросы.
MPL-макросы.
При определении макроса вы составляете текст, который хотите ассоциировать с именем
макроса. Затем, когда вы хотите включить макротекст в свою ассемблерную программу,
вы подставляете имя макроса. Ассемблер заместит имя макроса текстом, заданном в макроопределении.
При записи ассемблерных программ макросы дают несколько преимуществ:
возможность ввести удобное обозначение для группы команд, что уменьшает текст
и улучшает читабельность;
31
частое использование макросов может уменьшить количество ошибок, сделанных
программистом;
область видимости имен, используемых в макросе, ограничена этим макросом;
макросы хорошо подходят для создания простых кодовых таблиц.
Недостатком использования макросов при написании программы является то, что в лучшем случае они увеличивают память программ.
2.7.1. Директивы определения стандартных макросов
Ниже в таблице представлены директивы, предназначенные для определения макросов.
Директива
ENDM
EXITM
IRP
IRPC
REPT
LOCAL
MACRO
Описание
Завершает макроопределение
Вызывает немедленное завершение макрорасширения
Повторяет блок операторов для каждого аргумента заданного списка
Повторяет блок операторов для каждого символа заданного аргумента
Повторяет блок операторов заданное число раз
Специфицирует до 16 локальных символов макроса
Начинает макроопределение
2.7.2. Определение макроса
Чтобы можно было использовать макрос в программе, он предварительно должен быть
определен. Макроопределение начинается с директивы MACRO, которая объявляет имя
макроса и, возможно, до 16 формальных (необязательных) параметров. При определении
и вызове макроса параметры должны разделяться запятой. Если при вызове макроса необходимо пропустить какой-либо параметр, то разделительная запятая ставится без пробела;
пропущенному параметру присваивается значение NULL. Завершается макроопределение
директивой ENDM. Текст между директивами MACRO и ENDM называется макротелом.
Директива EXITM может использоваться для немедленного завершения макрорасширения. Обычно эта директива используется совместно с операторами условного ассемблирования. Ниже приведен общий пример обозначения макроса и последующего его вызова:
Имя_макрокоманды MACRO [список формальных параметров]
ТЕЛО МАКРОСА
содержание, текст макроса (что
конкретно надо будет замещать)
ENDM — завершение макроопределения
Имя_макрокоманды [список реальных параметров]
; вызов макроса
Пример:
Обозначение макроса
SUB_8 MACRO X, Y
CLR C
Вызов макроса
; R7 := R7 – R6
SUB_8 R7,R6
MOV A, X
SUBB A, Y
MOV X, A
ENDM
Метки, используемые в макросе, должны быть локальными. Эти метки видны только
внутри макроса. Вы можете определить до 16 локальных меток (или любых символов) с
помощью директивы LOCAL. Ассемблер генерирует внутреннее символическое имя для
32
локальных символов, определенных в макросе. Внутренний символ имеет форму ??0000 и
инкрементируется каждый раз при вызове макроса. Поэтому при повторных вызовах макроса ошибки не будут генерироваться, т.к. локальные метки макроса являются уникальными.
2.7.3. Повторение блоков
Ассемблер предоставляет возможность повторять определенный блок текста внутри макроса. Директивы: REPT, IRP, IRPC — используются для указания текста, повторяемого
внутри макроса. Каждая из этих директив должна завершаться директивой ENDM.
REPT
Эта директива повторяет блок текста заданное число раз. Далее представлен обобщенный
план формирования повторяющегося участка кода:
REPT число_повторений
ТЕКСТ
— повторяющийся текст
ENDM
Пример. Следующий макрос после вызова вставляет 5 инструкций NOP:
DELAY MACRO
REPT 5
NOP
ENDM
ENDM
IRP
Повторяет блок один раз для каждого аргумента заданного списка. Специфицируемый
параметр в теле макроса замещается каждым аргументом.
Пример. Следующий макрос замещает аргумент RNUM регистрами R0, R1, ... :
CLRREGS
MACRO
IRP RNUM,
MOV RNUM, #0
ENDM
ENDM
IRPC
Эта директива повторяет блок один раз для каждого символа заданного аргумента. Указанный параметр в теле макроса замещается каждым символом аргумента.
Пример. Следующий макрос замещает параметр CHR символами T, E, S, T:
DEBUGOUT
MACRO
IRPC CHR,
JNB
TI, $
; проверка передачи
CLR
TI
; очистка бита передатчика
; последовательного порта
MOV
A, #’CHR’
MOV
SBUF, A
ENDM
ENDM
33
2.7.4. Операторы
Ассемблер предоставляет ряд операторов для использования внутри макроопределений. В
следующей таблице дается список операторов и их описание.
Оператор
NUL
&
<>
%
;;
!
Описание
Когда при вызове макроса пропущен параметр, то он принимает значение NULL. Оператор
NUL используется в макросе для проверки параметра на NULL, как правило, внутри оператора
условного ассемблирования IF. Если параметр пропущен, NUL генерирует ненулевое значение, иначе – 0.
Символ амперсанда используется для конкатенации текста и параметров, причем параметры
присоединяются к тексту буквально.
Угловые скобки используются для выделения текста, который должен передаваться в макросы
буквально. Обычно такой текст содержит разделители, например запятые, которые не могут
быть переданы в макрос без заключения их в угловые скобки. При передаче этого текста во
вложенный макрос требуется одна пара угловых скобок для каждого уровня вложения.
Этот символ используется как приставка параметра для указания, что параметр должен интерпретироваться как выражение. При использовании этого оператора вычисляется числовое значение последующего выражения. Это значение передается в макрос вместо текста выражения.
Сдвоенная точка с запятой используется для указания, что оставшаяся часть строки должна
быть отброшена при расширении макроса. Этот оператор обычно используется перед комментариями, которые не требуется включать в расширение макроса. Может использоваться в качестве параметра.
Этот оператор используется для указания буквальной передачи спецсимвола в макрос. Этот
оператор дает вам возможность передать в макрос запятую и угловые скобки, которые нормально интерпретировались бы как разделители.
Пример:
Обозначение макроса
DEF_CONST MACRO N
CONST&N EQU N
ENDM
Расшифровка макроса
DEF_CONST 0 → CONST0 EQU 0
DEF_CONST 1 → CONST1 EQU 1
2.7.5. Си-макросы
Макроассемблер А51 имеет стандартный Си-макропрепроцессор, который практически
идентичен макропрепроцессору компилятора Си. Это дает возможность использовать общие заголовочные файлы с определением констант, которые можно использовать как в
ассемблерных, так и в Си-файлах (только целочисленные 16-разрядные). Далее приведено
обозначение Си-совместимого макроса:
#define ...
Ассемблер также допускает использование определений РСФ в стиле Си. Внешними по
своему определению макросы никогда быть не могут.
2.7.6. Вызов макроса
После определения макроса он может многократно вызываться в программе. Макровызов
содержит макроимя и любые, передаваемые в макрос параметры. При вызове макроса
позиции фактических параметров соответствуют позициям формальных параметров,
указанных в определении макроса. Ассемблер замещает параметры в макросе, начиная с
первого параметра. Первый фактический параметр замещает каждое местоположение
(вхождение) первого формального параметра в определении макроса, второй фактический
параметр замещает второй формальный параметр и т.д. Если число фактических
параметров превышает число формальных, то ассемблер игнорирует дополнительные
параметры. Если фактических параметров указано меньше по сравнению с числом
формальных параметров, тогда ассемблер замещает отсутствующие параметры символом
NULL.
34
2.8. УПРАВЛЯЮЩИЕ ДИРЕКТИВЫ АССЕМБЛЕРА
В этом разделе объясняется как использовать Ax51 для ассемблирования исходных файлов и обсуждаются управляющие директивы (средства управления) ассемблера, которые
могут специфицироваться в командной строке и внутри исходного файла.
Используя управляющие директивы, описанные в этом разделе, вы можете специфицировать выполняемые Ax51 операции (действия). Например, вы можете указать Ax51 генерировать листинговый файл, произвести (создать) информацию о перекрестных ссылках и
контролировать (управлять) количество информации, включаемое в объектный файл. Вы
также можете условно ассемблировать части (секции) кода, используя директивы условного ассемблирования.
Управляющие директивы ассемблера
Ax51 предоставляет ряд управляющих директив, которые могут использоваться для
управления работой ассемблера. Управляющие директивы можно указывать после имени
файла в строке запуска или в управляющей строке исходного файла. Управляющие строки
предваряются знаком «$».
Управляющие директивы Ax51 подразделяются на два класса: primary (первичные, исходные, начальные, заголовочные, основные) и general (широкого назначения, повсеместные,
обычные, общего назначения). Первичные директивы специфицируются в первых строках
исходного файла. Первичные директивы остаются в действии на всем протяжении ассемблирования. По этой причине первичные директивы могут использоваться только в
командной строке запуска или в управляющих строках в начале программы (исходного
файла). Только управляющие строки, не содержащие управляющую директиву
INCLUDE, могут предшествовать строке, содержащей первичную директиву. Управляющая директива INCLUDE отмечает конец любой спецификации первичной управляющей
директивы.
Если первичная директива специфицирована в строке запуска и в первых строках исходного файла, то используется спецификация строки запуска. Это позволяет вам перекрыть
первичные директивы через строку запуска.
Управляющие директивы широкого назначения используются для управления текущим
действием ассемблера (процессора). Обычно их состояние устанавливается и модифицируется во время ассемблирования. Строки, содержащие только управляющие директивы
широкого назначения, могут быть размещены в любом месте исходного файла. В следующей таблице представлены наиболее используемые управляющие директивы и их
краткое описание. Директивы сгруппированы по функциональному назначению.
ДОПОЛНИТЕЛЬНАЯ ЛИТЕРАТУРА ПО ДИСЦИПЛИНЕ
1. Толковый словарь по вычислительным системам / Под ред. В. Иллингуорта и др.: Пер. с
англ. А.К. Белоцкого и др.; Под ред. Е.К. Масловского. — М.: Машиностроение, 1990.
— 560 с.: ил.
2. Проектирование цифровых устройств на однокристальных микроконтроллерах / В.В.
Сташин, А.В. Урусов, О.Ф. Мологонцева. — М.: Энергоатомиздат, 1990. — 224 с.
3. Борковский А.Б. Англо-русский словарь по программированию и информатике (с толкованиями). — М.: Рус. яз., 1989. — 335 с.
35
Директива
COND
/NOCOND
DATE(date)+
Описание
Формирование и форматирование содержимого листингового файла
Управляющая директива COND предписывает ассемблеру включать неассемблируемые части
блоков IF-ELSEIF-ENDIF в листинговый файл. При этом строки неассемблируемого кода не
нумеруются. Директива NOCOND предписывает ассемблеру не включать неассемблируемые
части блоков IF-ELSEIF-ENDIF в листинговый файл. По умолчанию действует COND.
Соответствующий элемент управления в Vision2: Project/Options for Target .../Listing/Assembler
Listing/Conditional.
Предписывает ассемблеру включать текущую дату (date) в заголовок каждой страницы листингового файла. Дата заключается в круглые скобки. Только первые 8 символов в дате используюся, дополнительные символы игнорируются. По умолчанию дата включается в заголовок листинга из операционной системы.
GEN/NOGEN+
Соответствующий элемент управления в Vision2: Project/Options for Target .../A51/Misc Control
– Ввод управляющей директивы DATE.
Вставляет в листинговый файл после строки, содержащей EJECT, управляющий символ «перевод страницы», предписывающий принтеру перейти к началу следующей страницы. Эта директива игнорируется, если предварительно были указаны директивы NOLIST или NOPRINT.
Управляющая директива EJECT не может указываться в командной строке.
Управляющая директива GEN предписывает ассемблеру раскрывать в листинговом файле все
макровызовы. Директива NOGEN запрещает ассемблеру раскрывать в листинговом файле макровызовы. В листинг вставляется только макровызов. По умолчанию действует NOGEN.
LIST/NOLIST
Соответствующий элемент управления в Vision2: Project/Options for Target .../Listing/Assembler
Listing/Macros.
Управляющая директива LIST предписывает ассемблеру включить следующий текст программы
в листинговый файл. Директива NOLIST запрещает ассемблеру включать последующие строки
исходного файла в листинговый файл. Если строка, нормально не включаемая в листинг, вызывает ошибку при ассемблировании, то она включается в листинг вместе с сообщением об ошибке. По умолчанию действует LIST.
EJECT
TITLE(string)+
Соответствующий элемент управления в Vision2: Project/Options for Target .../A51/Misc Control
– Ввод управляющей директивы LIST/NOLIST.
Позволяет помещать надпись в верхний колонтитул листинга. Надпись заключается в круглые
скобки; ее длина не должна превышать 60 символов. Если директива TITLE не используется, то
по умолчанию в верхний колонтитул помещается имя исходного файла без расширения.
Соответствующий элемент управления в Vision2: Project/Options for Target .../A51/ Misc Control
– Ввод директивы.
Прочие
Предписывает ассемблеру включить содержимое файла, заключенного в круглые скобки, в
процесс ассемблирования. Содержимое указанного файла вставляется сразу же за строкой, где
находится директива INCLUDE. Допускается вложение файлов с директивой INCLUDE глубиной до 9 уровней. В конце файла END не ставится. Данная директива не может указываться в
командной строке. Директива INCLUDE обычно используется для:
INCLUDE(file)
включения описания РСФ различных производных семейства МК-51;
включения деклараций внешних подпрограмм, переменных и макрокоманд;
включения ассемблерного кода (более редкое применение).
Ассемблер осуществляет поиск включаемого файла в текущей директории и в директориях,
специфицированных директивой INCDIR. Если файл не найден, то его поиск продолжается в
директории path_of_the_EXE_file\..\ASM. При обычной установке инструментальных средств
этот маршрут является правильным для включаемых файлов различных производных МК-51
(Папка \C51\BIN\ содержит ассемблер, а папка \C51\ASM\ – файлы описания РСФ).
Не допускает использование ассемблером неявно определенных (по умолчанию) РСФ для микроконтроллера 8051. Это необходимо, когда вы хотите включить файл с определениями РСФ
для микроконтроллера семейства МК-51, отличного от стандартного микроконтроллера 8051.
NOMOD51
Соответствующий элемент управления в Vision2: Project/Options for Target .../A51/ Special Function Register/Define 8051 SFR Names.
36