Директивы ассемблера. Синтаксис ассемблера. Метки. EXIT – Выйти из файла

При написании программ на языке Ассемблер используются директивы, которые указывают компилятору положение программы в памяти, определяют макросы, инициализируют память и др. Список директив и их описание приведен в табл. 1.8. Запись всех директив начинается с точки. Кратко перечислим выполняемые директивами функции в каждом из сегментов.

Сегмент программы открывается директивой.CSEG. Если программа начинается с этого сегмента, директива может отсутствовать. В сегменте программы с помощью директивы.ORG можно указать начало сегмента.

Директива.DB в сегменте определяет один байт или группу байтов, констант, записываемых во Flash-память. Директива.DW определяет слово или группу слов, записываемых в память в качестве констант. Начало записи констант определяется меткой, стоящей перед соответствующей директивой. Перечисляемые константы разделяются запятыми.

Директива.DEF присваивает регистру символическое имя. Директивы.EQU, .SET присваивают значение имени. Имя, которому присвоено значение директивой.EQU, не может быть переназначено, и значение не может быть изменено. Имя, присвоенное директивой.SET, может быть изменено другой директивой.SET.

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

Директива.INCLUDE с именем файла используется для включения в текст программы другого файла.

Таблица 1.8. Список директив

Директива

Описание

Резервировать байты в ОЗУ

Сегмент программы

Определить байт – константу во Flash-памяти или

Назначить регистру символическое имя

Определяет устройство, для которого компилируется

программа

Сегмент данных

Определяет слово во Flash-памяти или EEPROM

Конец макроса

Установить постоянное выражение

Сегмент EEPROM

Выход из файла

Вложить другой файл

Включить генерацию листинга

Включить разворачивание макросов в листинге

Начало макроса

Выключить генерацию листинга

Установить положение в сегменте

Установить для переменной эквивалентное выражение

Директивы.MACRO и.ENDMACRO обрамляют макроопределение. Макроопределение может иметь до 10 параметров с фиксированными именами @0,…,@9. При вызове макроопределения параметры задают в виде списка в порядке нумерации.

Сегмент данных начинается директивой.DSEG. В сегменте могут быть использованы директивы.ORG и.BYTE. Директива.BYTE определяет количество байтов, к которым будет производиться обращение при выполнении программы. Резервируемая область начинается по адресу, определяемому меткой перед директивой.

Сегмент типа EEPROM начинается директивой.ESEG. В сегменте могут быть использованы директивы.ORG, .DB, .DW. Директива.DB в сегменте определяет один или группу байтов, записываемых в EEPROM. Директива.DW определяет слово или группу слов, записываемых в память EEPROM парами по 2 байта. Начало записи байтов и слов определяется меткой, стоящей перед соответствующей директивой.

Директивы.LIST, .NOLIST, .LISTMAC используют для управления выводом листинга.

Здесь представлена информация по ассемблеру всей серии AVR, т.к. все микроконтроллеры этой серии программно совместимы.
Ассемблер – это инструмент, с помощью которого создаётся программа для микроконтроллера. Ассемблер транслирует ассемблируемый исходный код программы в объектный код, который может использоваться в симуляторах или эмуляторах AVR. Также ассемблер генерирует код, который может быть непосредственно введен в программную память микроконтроллера.
При работе с ассемблером нет никакой необходимости в непосредственном соединении с микроконтроллером.

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

Строка программы может быть в одной из четырёх форм:

[ Метка:] директива [операнды] [Комментарий]
[ Метка:] команда [операнды] [Комментарий]
Комментарий
Пустая строка

Комментарий имеет следующую форму:

Таким образом любой текст после символа “ ; ” игнорируется ассемблером и имеет значение только для пользователя.

Операнды можно задавать в различных форматах:

Десятичный (по умолчанию): 10,255
- шестнадцатеричный (два способа): 0x0а, $0а
- двоичный: 0b00001010, 0b11111111
- восьмеричный (впереди ноль): 010, 077

2 Система команд

Система команд микроконтроллеров ATMEL семейства AVR очень большая и в то же время эффективная. Одной из отличительных особенностей микроконтроллеров AVR является то, что почти все команды выполняются за 1 тактовый цикл. Исключение составляют команды перехода. Это существенно увеличивает производительность микроконтроллера даже при относительно невысокой тактовой частоте.

Все команды можно классифицировать на 5 типов:
1. арифметические команды;
2. логические команды;
3. команды перехода;

  • команды передачи данных;
  • побитовые команды и команды тестирования битов.

3 Директивы ассемблера

Ассемблер поддерживает множество директив. Директивы не транслируются непосредственно в коды операции. Напротив, они используются, чтобы корректировать местоположение программы в памяти, определять макрокоманды, инициализировать память и так далее. То есть это указания самому ассемблеру, а не команды микроконтроллера.
Все директивы ассемблера приведены в табл. 1.2.

Таблица 1.2.
Директивы ассемблера


Директива

Описание

Зарезервировать байт под переменную

Сегмент кодов

Задать постоянным(и) байт(ы) в памяти

Задать символическое имя регистру

Задать для какого типа микроконтроллера компилировать

Сегмент данных

Задать постоянное(ые) слово(а) в памяти

Сегмент EEPROM

Выход из файла

Включить исходный код из другого файла

Включить генерацию.lst - файла

Выключить генерацию.lst - файла

Начальный адрес программы

Установите символ равный выражению

Синтаксис всех директив следующий:
.[директива]
То есть перед директивой должна стоять точка. Иначе ассемблер воспринимает это как метку.
Дадим несколько пояснений наиболее важным директивам ассемблера

CSEG - Code segment

Директива CSEG указывает на начало сегмента кодов. Ассемблируемый файл может иметь несколько кодовых сегментов, которые будут объединены в один при ассемблировании.
Синтаксис:

CSEG
Пример:
vartab: .BYTE 4 ; Резервируется 4 байта в СОЗУ
const: .DW 2 ; Записать 0x0002 в программной памяти
mov r1,r0 ; Что-то делать

DSEG - Data Segment

Директива DSEG указывает на начало сегмента данных. Ассемблируемый файл может содержать несколько сегментов данных, которые потом будут собраны в один при ассемблировании. Обычно сегмент данных состоит лишь из директив BYTE и меток.

Синтаксис:

DSEG
Пример:

table: .BYTE tab_size ; Резервировать tab_size байтов.
.CSEG
ldi r30,low(var1)
ldi r31,high(var1)
ld r1,Z

ESEG - EEPROM Segment

Директива ESEG указывает на начало сегмента EEPROM памяти. Ассемблируемый файл может содержать несколько EEPROM сегментов, которые будут собраны в один сегмент при ассемблировании. Обычно сегмент EEPROM состоит из DB и DW директив (и меток). Сегмент EEPROM памяти имеет свой собственный счетчик. Директива ORG может использоваться для размещения переменных в нужной области EEPROM.
Синтаксис:

DSEG ; Начало сегмента данных
var1: .BYTE 1 ; Резервировать 1 байт под переменную var1
table: .BYTE tab_size ; Зарезервировать tab_size байт.
.ESEG
eevar1: .DW 0xffff ; Записать 1 слово в EEPROM

ORG - Установить адрес начала программы

Директива ORG присваивает значения локальным счетчикам. Используется только совместно с директивами.CSEG, .DSEG, .ESEG.
Синтаксис:

DSEG ; Начало сегмента данных
.ORG 0x37 ; Установить адрес СОЗУ на 37h
variable: .BYTE 1 ; Зарезервировать байт СОЗУ по адресу 37h
.CSEG
.ORG 0x10 ; Установить счетчик команд на адрес 10h
mov r0,r1 ; Чего-нибудь делать

DB - определить байт(ы) в программной памяти или в EEPROM

Директива DB резервирует ресурсы памяти в программной памяти или в EEPROM. Директиве должна предшествовать метка. DB задает список выражений, и должна содержать по крайней мере одно выражение. Размещать директиву следует в сегменте кодов или в EEPROM сегменте.

Список выражений представляет собой последовательность выражений, разделенных запятыми. Каждое выражение должно быть величиной между –128 и 255.

Если директива указывается в сегменте кодов и список выражений содержит более двух величин, то выражения будут записаны так, что 2 байта будут размещаться в каждом слове Flash-памяти.

Синтаксис:

LABEL: .DB список выражений

CSEG
consts: .DB 0, 255, 0b01010101, -128, 0xaa
.ESEG
const2: .DB 1,2,3

DW – Определить слово(а) в программной памяти или в EEPROM

Директива DW резервирует ресурсы памяти в программной памяти или в EEPROM. Директиве должна предшествовать метка. DW задает список выражений, и должна содержать по крайней мере одно выражение. Размещать директиву следует в сегменте кодов или в EEPROM сегменте.

Список выражений представляет собой последовательность выражений, разделенных запятыми. Каждое выражение должно быть величиной между –32768 и 65535.

Синтаксис:

LABEL: .DW список выражений

CSEG
varlist: .DW 0, 0xffff, 0b1001110001010101, -32768, 65535
.ESEG
eevarlst: .DW 0,0xffff,10

DEF – Присвоить имя регистру

Директива DEF позволяет присвоить символическое имя регистру. Регистр может иметь несколько символических имен.
Синтаксис:

DEF Имя=Регистр

DEF temp=R16
.DEF ior=R0
.CSEG
ldi temp,0xf0 ; Загрузить 0xf0 в регистр temp
in ior,0x3f ; Прочитать SREG в регистр ior
eor temp,

EQU – Присвоить имя выражению

Директива EQU присваивает значение метке. Эта метка может быть использована в других выражениях. Значение этой метки нельзя изменить или переопределить.

Синтаксис:

EQU метка=выражение

EQU io_offset = 0x23
.EQU porta = io_offset + 2
.CSEG ; Начало сегмента кодов
clr r2 ; Очистить регистр r2
out porta,r2 ; Записать в порт А

INCLUDE –вставить другой файл

Директива INCLUDE говорит Ассемблеру начать читать из другого файла. Ассемблер будет ассемблировать этот файл до конца файла или до директивы EXIT. Включаемый файл может сам включать директивы INCLUDE.
Синтаксис:

INCLUDE "имя файла"

; iodefs.asm:
.EQU sreg = 0x3f ; Регистр статуса
.EQU sphigh = 0x3e ; Старший байт указателя стека.
.EQU splow = 0x3d; ; Младший байт указателя стека.
; incdemo.asm
.INCLUDE iodefs.asm ; Включить файл «iodefs.asm»
in r0,sreg ; Прочитать регистр статуса

EXIT – выйти из файла

Директива EXIT позволяет ассемблеру остановить ассемблирование текущего файла. Обычно ассемблер работает до конца файла. Если он встретит директиву EXIT, то продолжит ассемблировать со строки, следующей за директивой INCLUDE.
Синтаксис:

EXIT ; выйти из этого файла

DEVICE - Указать для какого микроконтроллера ассемблировать
Директива позволяет пользователю сообщить ассемблеру, для какого типа устройства пишется программа. Если ассемблер встретит команду, которая не поддерживается указанным типом микроконтроллера, то будет выдано сообщение. Также сообщение появится в случае, если размер программы превысит объем имеющейся в этом устройстве памяти.
Синтаксис:

DEVICE AT90S1200 |AT90S2313 | AT90S2323 | AT90S2333 | AT90S2343 | AT90S4414 | AT90S4433 | AT90S4434 | AT90S8515 | AT90S8534 | AT90S8535 | ATtiny11 | ATtiny12 | ATtiny22 | ATmega603 | ATmega103

DEVICE AT90S8535 ; использовать AT90S8535
.CSEG
.ORG 0000
jmp label1; При ассемблировании появиться сообщение, что;AT90S8535 не поддерживает команду jmp
1.5.2.4 Некоторые особенности программирования

Память данных почти полностью доступна программе пользователя и большинство команд ассемблера предназначено для обмена данными с ней. Команды пересылки данных предоставляют возможность непосредственной и косвенной адресации ячеек СОЗУ, непосредственной адресации регистров ввода/вывода и регистров общего назначения. Так как каждому регистру сопоставлена ячейка памяти, то обращаться к ним можно не только командами адресации регистров, но и командами адресации ячеек СОЗУ.

Например, команда:

MOV R10,R15 - скопировать регистр R15 в регистр R10
делает абсолютно то же самое, что и команда:
LDS R10,$0015 - загрузить в регистр R10 содержимое ячейки с адресом $0015
То же самое относится и к регистрам ввода/вывода. Для них предусмотрены специальные команды:
IN Rd,P - загрузить данные из порта I/O с номером Р в регистр Rd
OUT P,Rd - записать данные из регистра Rd в порт I/O с номером Р.
При использовании этих команд номер порта указывается в диапазоне 0Пример применения разных команд:

LDI R16,$FF
OUT $12,R16 - записать в PORTD число 255.
STS $0032,R16 - записать непосредственно в ячейку $0032 число 255.
Адрес регистра ввода/вывода в СОЗУ получается прибавлением к номеру порта числа $20.
Память программ является ПЗУ и изменяется только при программировании кристалла. Константы можно располагать в памяти программ в виде слов.

Например: .dw $033f,$676d,$7653,$237e,$777f
Для работы с данными, расположенными в памяти программ, предусмотрена команда
LPM - загрузить байт памяти программ, на который указывает регистр Z в регистр R0.
Адрес байта константы определяется содержимым регистра Z. Старшие 15 битов определяют слово адреса (от 0 до 4к) состояние младшего бита определяет выбор младшего байта (0) или старшего байта (1).
При работе с портами ввода/вывода следует учитывать следующую особенность. Если вывод порта сконфигурирован как выход, то его переключение производится через регистр данных (PORTA, PORTB, PORTC, PORTD), если вывод сконфигурирован как вход, то его опрос следует производить через регистр выводов входа порта (PINA, PINB, PINC, PIND).
Особенностью использования арифметических и логических команд является то, что некоторые из них работают только с регистрами R16-R31.

CPI Rd,K - сравнить регистр Rd с константой К. 16 Команды CBI и SBI работают только с младшими 32-мя регистрами ввода/вывода.
При использовании подпрограмм нужно обязательно определять стек! Для этого нужно занести значения адреса вершины стека в регистры SPH и SPL.

Язык программирования ассемблер всегда включает в себя машинные коды микроконтроллера, но этим не ограничивается набор команд этого языка. Дело в том, что нужно уметь управлять самим процессом трансляции программы. Полный список директив приведён в описании языка, а здесь будут подробно рассмотрены некоторые из них.

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

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


Листинг 1. Назначение переменных при помощи директивы equ

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

При помощи директивы equ можно назначать не только переменные, но и константы. Как уже говорилось ранее, будет ли использован идентификатор как переменная или как константа зависит от команд и видов адресации , которые использует программист.

Один раз назначенный идентификатор уже не может быть изменён в дальнейшем и при повторной попытке назначения точно такого же имени идентификатора будет выдано сообщение об ошибке.

Директива set . Если требуется в различных местах программы назначать одному и тому же идентификатору различные числа, то нужно пользоваться директивой set. Использование этой директивы полностью идентично использованию директивы equ, поэтому иллюстрироваться примером не будет.

Константы, назначаемые директивой equ, могут быть использованы только в одной команде. Достаточно часто требуется работа с таблицей констант, такой как таблица перекодировки, таблицы элементарных функций или синдромы помехоустойчивых кодов. Такие константы используются не на этапе трансляции, а хранятся в памяти программ микроконтроллера. Для занесения констант в память программ микроконтроллера используются директивы db и dw.

Директива db используется для занесения в память программ однобайтных констант. Пример использования директивы db приведён в листинге 2.


Листинг 2. Назначение констант при помощи директивы db

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

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

Эта же директива позволяет легко записывать надписи, которые в дальнейшем потребуется высвечивать на встроенном дисплее или экране дисплея универсального компьютера, подключённого к разрабатываемому устройству через какой либо интерфейс. Пример использования директивы db для занесения надписей в память программ микроконтроллера приведён на рисунке 3.

Рисунок 3. Применение директивы db для занесения надписей в память программ микроконтроллера.

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

Рисунок 4. Применение директивы dw.

На рисунке 4 приведён фрагмент листинга программы для того, чтобы можно было проследить какие байты заносятся в память программ микроконтроллера. В самой правой колонке листинга приведены адреса в которые будут занесены числа, являющиеся операндами директивы dw. В следующей колонке приведены двухбайтовые числа, которые будут заноситься в память программ микроконтроллера. Обратите внимание, что несмотря на то, что первые два операнда состоят только из одной цифры, в память микроконтроллера заносятся четыре шестнадцатеричных цифры (двухбайтовое число).

При трансляции исходного текста программ предполагается, что первая команда расположена по нулевому адресу. Адрес последующих команд зависит от длины и количества предыдущих команд. Пример листинга начального участка программы приведён на рисунке 5.

Рисунок 5. Пример листинга программы.

Иногда требуется расположить команду по определённому адресу. Наиболее часто это требуется при использовании прерываний, когда первая команда программы-обработчика прерываний должна быть расположена точно на векторе прерывания . Это можно сделать используя команду nop для заполнения промежутков между векторами прерывания, но лучше воспользоваться директивой ORG.

Директива org предназначена для записи в счетчик адреса сегмента значения своего операнда. То есть при помощи этой директивы можно разместить команду (или данные) в памяти микроконтроллера по любому адресу. Пример использования директивы ORG для размещения подпрограмм обработки прерываний на векторах прерываний показан на рисунке 6.

Рисунок 6. Пример использования директивы ORG.

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

Директива using При использовании прерываний критичным является время, занимаемое программой, обработчиком прерываний. Это время можно значительно сократить, выделив для обработки прерываний отдельный банк регистров. Выделить отдельный банк регистров можно при помощи директивы USING. Номер банка используемых регистров указывается в директиве в качестве операнда. Пример использования директивы USING для подпрограммы обслуживания прерываний от таймера 0 приведён на рисунке 7.

Рисунок 7. Пример использования директивы USING.

Директива CALL. В системе команд микроконтроллера MCS-51 используется три команды безусловного перехода. Выбор конкретной команды зависит от расположения ее в памяти программ, однако программист обычно этого не знает. В результате во избежание ошибок приходится использовать самую длинную команду LJMP . Это приводит к более длинным программам и к дополнительной нагрузке на редактор связей. Транслятор сам может подобрать наилучший вариант команды безусловного перехода. Для этого вместо команды микроконтроллера следует использовать директиву call.

Остальные директивы предназначены для управления сегментами, и поэтому будут рассмотрены позднее при обсуждении работы с многомодульными программами.

Литература:

Вместе со статьей "Директивы языка программирования ASM-51" читают:


http://сайт/Progr/progr.php

Директивы представляют собой команды управления компилятором. Объявление каждой из них должно начинается с точки. Практика показывает, что в любом ассемблере наиболее интенсивно используется только порядка 10…20 директив. Все остальные либо не являются обязательными, либо отвечают за управление, лишь незначительными свойствами компилятора. К “основным”, характерным и для ассемблеров других процессоров, относятся директивы.equ, .org, .def, .сseg, .dseg и т.д. Ну, а такие директивы, как.dq, .exit, .listmac в реальных программах встречаются действительно очень редко. Ниже приведен перечень, описание и примеры использования директив фирменного ассемблера микроконтроллеров AVR.

Директива.include подставляет текстовый файл в то место программы, где происходит ее употребление. В дополнении к этому сам файл подстановки также может содержать директиву.include. Если файл расположен в директории проекта или в одной из служебных папок, то вместо полного пути, допускается указывать, лишь ссылку на его имя.

Директива.include
Синтаксис написания:
.include "{путь к файлу}"
Пример использования:

Include "m8def.inc" ;вставка стандартного заголовочного файла

Директива.exit указывает ассемблеру место окончания файла исходного текста. Все операторы, находящиеся после директивы, становятся невидимыми для компилятора. Если.exit встречается в подключаемом файле, то сборка проекта заканчивается строкой, где расположена директива.include. В случае отсутствия директивы.exit, конечной точкой сборки считается последняя строка исходного текста.

Директива.exit
Синтаксис написания:
.exit
Пример использования:

Exit ;конец файла

Директивы.nolist и.list служат для управления файлом листинга, который обычно генерируется после сборки проекта. Первая из них запрещает, а другая, соответственно, разрешает вывод информации в файл. Директива.list отменяет действие.nolist и наоборот.

Директивы.nolist, .list
Синтаксис написания:
.nolist, .list
Пример использования:

Nolist ;запретить вывод текста файла “m8def.inc” .include "m8def.inc" ;в файл листинга программы.list ;продолжить вывод информации

Директива.equ присваивает символьному имени некоторое числовое значение. Символьное имя должно быть уникальным и не может быть изменено в процессе написания программы. Директива не может применяться для назначения символьных имен регистрам общего назначения.

Директива.equ
Синтаксис написания:
.equ {символьное имя} = {выражение}
Пример использования:

Equ DDRB = 0x17 ;присвоение имени DDRB значения 0x17 .equ PORTB = DDRB + 1 ;присвоение имени PORTB значения 0x18

Директива.set производит то же самое действие, что и.equ. Но в отличии от последней, символьное имя может быть переопределено в любом месте программы.

Директива.set
Синтаксис написания:
.set {символьное имя} = {выражение}
Пример использования:

Set OFFSET = 0x100 ;присвоение имени OFFSET значения 0x100 . .set OFFSET = OFFSET + 1 ;переопределение значения OFFSET

Директива.def присваивает символьное имя одному из регистров общего назначения. В дальнейшем ходе программы данное имя может быть отменено директивой.undef.

Директивы.def, .undef
Синтаксис написания:
.def {символьное имя} = {регистр}
.undef {символьное имя}
Пример использования:

Def temp = R16 ;присвоение регистру R16 имя temp .undef temp ;отмена дальнейшего использования имени temp

Директивы.db, .dw, .dd, .dq предназначены для резервирования памяти микроконтроллера под инициализированные данные. Все они могут применяться только в сегментах кода и EEPROM-памяти. Разница между этими директивами заключается в разрядности, представляемых данных. Директива.db резервирует байты, .dw – слова, .dd – двойные слова. В редких случаях может так же оказаться удобным использование директивы.dq, резервирующей 64-разрядные данные.

Директивы.db, .dw, .dd, .dq
Синтаксис написания:
{метка}: .db {8-разрядные данные}
{метка}: .dw {16-разрядные данные}
{метка}: .dd {32-разрядные данные}
{метка}: .dq {64-разрядные данные}
Пример использования:

Label: .db 0xFA, 250, -6, 0b11111010 .dw 0xFADE, 64222, -1314, 0b1111101011011110 .dd 0xFADEEFCA, 4208914378, -86052918 .dq 0xFADEEFCAEFBACDEF, 18077149609196178927, -521103510453211

Директива.byte резервирует память под неинициализированные данные в сегментах SRAM и EEPROM.

Директива.byte
Синтаксис написания:
{метка}: .byte {количество резервируемых данных}
Пример использования:

Equ PAGESIZE = 0x20 buffer: . byte 2*PAGESIZE ;резервирование 64 байт в SRAM

Директивы.dseg, .eseg, .cseg определяют начало сегментов данных, EEPROM-памяти и кода соответственно. В исходном файле каждый из сегментов может быть представлен только в одном экземпляре. В случае если все эти директивы отсутствуют в программе, компилятор по умолчанию считает, что все операторы расположены в секции кода.

Директивы.dseg, .eseg, .cseg
Синтаксис написания:
.dseg
.eseg
.cseg
Пример использования:

Dseg ;начало сегмента данных buffer: . byte 32 ;резервирование 32 байт под буфер в SRAM .cseg ;начало сегмента кода rjmp initial . string: .db "ATmega8",0 ;строка, хранящаяся во FLASH-памяти.eseg ;начало сегмента EEPROM-памяти _var: .byte 2 ;резервирование 2-ух байт под переменную _var _cnst: .db 0xAA ;резервирование байта под переменную _cnst = 0xAA

Директива.org позволяет задать компилятору начальный адрес в пределах сегментов кода, данных и EEPROM-памяти. В случае применения в сегменте кода, директива определяет адрес размещения 16-разрядного слова программ.

Директива.org
Синтаксис написания:
.org {начальный адрес}
Пример использования:

Equ SRAM_START = 0x60 .equ RAMEND = 0x045F .dseg ;начало сегмента данных.org SRAM_START ;резервирование 32 байт в SRAM под буфер, buffer: . byte 32 ;начиная с адреса 0x60 .cseg ;начало сегмента кода.org 0 ;вектор сброса по адресу 0 rjmp initial . .org 0x50 ;начало основной программы с адреса 0x50 initial: ldi temp,high(RAMEND) ;инициализация стека out SPH,temp ldi temp,low(RAMEND) out SPL,temp .

Директивы.macro, .endmacro (.endm), определяющие начало и конец макроса соответственно.

Директивы.macro, .endmacro (.endm)
Синтаксис написания:
.macro {имя макроса}
Пример использования:

Macro set_bit ;объявление макроса установки бита порта sbi @0,@1 ;установить бит @1 регистра порта @0 sbi @0-1,@1 ;настроить на вывод линию @1 регистра DDRx .endm . set_bit PORTB,0 ;установить на линии 0 порта B лог.1

Директива.listmac разрешает расширенный вывод текста макросов в файле листинга. В этом случае содержимое каждого макроопределения, встретившегося в программе, отображается целиком. Если директива не используется, то код в нутрии макроса не приводится.

Директива.listmac
Синтаксис написания:
.listmac
Пример использования:

Listmac ;разрешить разворачивать текст макросов в файле листинга

Директивы.message, .warning, .error предназначены для вывода в окно сборки проекта дополнительной информации о ходе компиляции программы. Директива.message генерирует сообщение для строки, в которой был встречен ее вызов. Применение.warning приводит к выдачи предупреждения, а.error – к сообщению об ошибки. В последнем случае сборка проекта прекращается.

Директивы.message, .warning, .error
Синтаксис написания:
.message "{текст сообщение}"
.warning "{текст предупреждения}"
.error "{текст соодщения об ошибки}"
Пример использования:

Message "Macros has been called here." .warning "Too high frequency!" .error "Wrong macro argument!"

Группа директив условной компиляции.ifdef, .ifndef, .if, .else, elif, .endif используются для вставок программного кода в зависимости от различных условий. Директива.ifdef проверяют наличие объявления некоторого символьного имени. За директивой может следовать набор команд, которые будут подставлены в текст, если условие проверки “истина” (имя было объявлено). Директива.ifndef противоположна.ifdef проверяет отсутствие объявления символьного имени. Директива.if производит подстановку кода, когда выполняется условие сравнения, указанное в качестве ее параметра. Команды, которые должны выполняться, в случае если условие директивы.if “ложно” – располагаются после директивы.else. Ветвление типа “если” - “то” может иметь несколько уровней вложения благодаря директиве.elif. Каждый блок проверки, начинающийся с.ifdef, .ifndef, .if, должен быть закрыт директивой.endif.

Директивы if, .ifdef, .ifndef, .else, elif, .endif
Синтаксис написания:
.ifdef {символ} (или.ifndef {символ})
.if {условие}
.else {выражение} (или.elif { условие})
.endif
Пример использования:

Macro del_ms ;макрос, формирующий задержку времени в мс.ifndef FREQ ;если не объявлена константа FREQ (частота в Гц), .warning "Undefined FREQ constan!" ;выдаем предупреждение и.equ FREQ = 1000000 ;присваиваем по умолчание значение 1 МГц.endif .equ DELAY = (@0*FREQ)/4000 ;величина задания задержки времени.if DELAY > 65535 ;если DELAY размером больше 2 байт, то.error “Integer overflow in DELAY!” ;реализация макроса не возможна.else push XL ;сохраняем в стеке рабочие регистры XL, XH push XH ldi XH,high(DELAY) ;цикл задержки времени ldi XL,low(DELAY) sbiw XH:XL,1 brne PC-1 pop XH pop XL ;восстанавливаем из стека рабочие регистры XH, XL .endif .endm . .equ FREQ = 2000000 ;объявление тактовой частоты 2 МГц. del_ms 25 ;формирование задержки времени в 25 мс

Ассемблеры MASM, TASM и WASM отличаются между собой. Однако создание простых программ для них практически не имеет отличий, за исключением самого ассемблирования и компоновки.

Итак, наша первая программа для MASM, TASM и WASM, которая выводит английскую букву «A» в текущей позиции курсора, то есть в левом верхнем углу экрана:

Model tiny .code ORG 100h start: MOV AH,2 MOV DL,41h INT 21h INT 20h END start Этот текст можно набрать в любом простом текстовом редакторе – например в БЛОКНОТЕ (NotePad) от WINDOWS (но не в Word и не в другом «навороченном»). Однако я рекомендую «продвинутый» текстовый редактор с подсветкой синтаксиса, например, PSPad (см. раздел ). Затем сохраняем этот файл с расширением.asm, например, в папке MYPROG. Назовем файл atest. Итак, мы получили: C:\MYPROG\atest.asm.

ПРИМЕЧАНИЕ
Обратите внимание, что в первой команде мы записали 2 вместо 02h. MASM, TASM и WASM, как и Emu8086, допускают такие «вольности». Хотя можно написать 02h – ошибки не будет.

Пояснения к программе :

.model tiny – 1-ая строка. Директива.model определяет модель памяти для конкретного типа файлов. В нашем случае это файл с расширением COM, поэтому выбираем модель tiny, в которой объединены сегменты кода, данных, и стека. Модель tiny предназначена для создания файлов типа СОМ.

.code – 2-ая строка. Эта директива начинает сегмент кода.

ORG 100h – 3-ая строка. Эта команда устанавливает значение программного счетчика в 100h, потому что при загрузке СОМ-файла в память, DOS выделяет под блок данных PSP первые 256 байт (десятичное число 256 равно шестнадцатеричному 100h). Код программы располагается только после этого блока. Все программы, которые компилируются в файлы типа СОМ, должны начинаться с этой директивы.

start: MOV AH, 02h – 4-я строка. Метка start располагается перед первой командой в программе и будет использоваться в директиве END, чтобы указать, с какой команды начинается программа. Инструкция MOV помещает значение второго операнда в первый операнд. То есть значение 02h помещается в регистр АН. Для чего это делается? 02h - это ДОСовская функция, которая выводит символ на экран. Мы пишем программу для DOS, поэтому используем команды этой операционной системы (ОС). А записываем мы эту функцию (а точнее ее номер) именно в регистр АН, потому что прерывание 21h использует именно этот регистр.

MOV DL, 41h – 5-я строка. Код символа «A» заносится в регистр DL. Код символа «A» по стандарту ASCII – это число 41h.

INT 21h – 6-я строка. Это и есть то самое прерывание 21h – команда, которая вызывает системную функцию DOS, заданную в регистре АН (в нашем примере это функция 02h). Команда INT 21h – основное средство взаимодействия программ с ОС.

INT 20h – 7-я строка. Это прерывание, которое сообщает операционной системе о выходе из программы, и о передаче управления консольному приложению. В том случае, если программа уже откомпилирована и запущена из ОС, команда INT 20h вернет нас в ОС (например, в DOS).

END start – 8-я строка. Директива END завершает программу, одновременно указывая, с какой метки должно начинаться ее выполнение.



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: