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

Ассемблеры 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 завершает программу, одновременно указывая, с какой метки должно начинаться ее выполнение.

При написании программ на языке Ассемблер используются директивы, которые указывают компилятору положение программы в памяти, определяют макросы, инициализируют память и др. Список директив и их описание приведен в табл. 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 используют для управления выводом листинга.

Директивы представляют собой команды управления компилятором. Объявление каждой из них должно начинается с точки. Практика показывает, что в любом ассемблере наиболее интенсивно используется только порядка 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 мс

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

Параметры передаваемые директиве – это последовательность выражений разделённых запятыми. Каждое выражение должно быть или числом в диапазоне (-128..255), или в

результате вычисления должно давать результат в этом же диапазоне, в противном случае число усекается до байта, причём БЕЗ выдачи предупреждений.

Если директива получает более одного параметра и текущим является программный сегмент, то параметры упаковываются в слова (первый параметр – младший байт), и если

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

директива DB.

Синтаксис:
МЕТКА: .DB список_выражений

Пример:
.CSEG
consts: .DB 0, 255, 0b01010101, -128, 0xaa

Параметры передаваемые директиве – это последовательность выражений разделённых запятыми. Каждое выражение должно быть или числом в диапазоне (-32768..65535), или

в результате вычисления должно давать результат в этом же диапазоне, в противном случае число усекается до слова, причем БЕЗ выдачи предупреждений.

Синтаксис:
МЕТКА: .DW expressionlist

Пример:
.CSEG
varlist: .DW 0, 0xffff, 0b1001110001010101, -32768, 65535

Синтаксис:
.ENDMACRO

Пример:
.MACRO SUBI16 ; Начало определения макроса
subi r16,low(@0) ; Вычесть младший байт первого параметра
sbci r17,high(@0) ; Вычесть старший байт первого параметра
.ENDMACRO

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

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

переназначена и её значение не может быть изменено.

Синтаксис:
.EQU метка = выражение

Пример:
.EQU io_offset = 0x23
.EQU porta = io_offset + 2

CSEG ; Начало сегмента данных
clr r2 ; Очистить регистр r2
out porta,r2 ; Записать в порт A

ESEG – Сегмент EEPROM

Директива ESEG определяет начало сегмента EEPROM. Исходный файл может состоять из нескольких сегментов EEPROM, которые объединяются в один сегмент при компиляции.

Сегмент EEPROM обычно состоит только из директив ,

href="#DW - Define constant word(s) in program memory and EEPROM">DW

и меток. Сегменты EEPROM имеют свои собственные

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

переменных в необходимом месте EEPROM. Директива не имеет параметров.

Синтаксис:
.ESEG

Пример:
var1: .BYTE 1 ; зарезервировать 1 байт для var1
table: .BYTE tab_size ; зарезервировать tab_size байт.

ESEG
eevar1: .DW 0xffff ; проинициализировать 1 слово в EEPROM

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

Встретив директиву EXIT компилятор прекращает компиляцию данного файла. Если директива использована во вложенном файле (см. директиву

href="#INCLUDE - Include another file">INCLUDE

), то компиляция продолжается со строки следующей после директивы INCLUDE.

Если же файл не является вложенным, то компиляция прекращается.

Синтаксис:
.EXIT

Пример:
.EXIT ; Выйти из данного файла

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

Встретив директиву INCLUDE компилятор открывает указанный в ней файл, компилирует его пока файл не закончится или не встретится директива

href="#EXIT - Exit this file">EXIT

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

INCLUDE. Вложенный файл может также содержать директивы INCLUDE.

Синтаксис:
.INCLUDE "имя_файла"

Пример:
; файл iodefs.asm:
.EQU sreg = 0x3f ; Регистр статуса
.EQU sphigh = 0x3e ; Старший байт указателя стека
.EQU splow = 0x3d ; Младший байт указателя стека

; файл incdemo.asm
.INCLUDE iodefs.asm ; Вложить определения портов
in r0,sreg ; Прочитать регистр статуса

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

Директива LIST указывает компилятору на необходимость создания листинга. Листинг представляет из себя комбинацию ассемблерного кода, адресов и кодов операций. По

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

Синтаксис:
.LIST

Пример:

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

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

параметры.

Синтаксис:
.LISTMAC

Пример:
.MACRO MACX ; Определение макроса
add r0,@0 ; Тело макроса
eor r1,@1

LISTMAC ; Включить разворачивание макросов
MACX r2,r1 ; Вызов макроса (в листинге будет показано теломакроса)

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

С директивы MACRO начинается определение макроса. В качестве параметра директиве передаётся имя макроса. При встрече имени макроса позднее в тексте программы,

компилятор заменяет это имя на тело макроса. Макрос может иметь до 10 параметров, к которым в его теле обращаются через @0-@9. При вызове параметры перечисляются

через запятые. Определение макроса заканчивается директивой .

По умолчанию в листинг включается только вызов макроса, для разворачивания макроса необходимо использовать директиву . Макрос в листинге показывается знаком +.

Синтаксис:
.MACRO макроимя

Пример:
.MACRO SUBI16 ; Начало макроопределения
subi @1,low(@0) ; Вычесть младший байт параметра 0 из параметра 1
sbci @2,high(@0) ; Вычесть старший байт параметра 0 из параметра 2
.ENDMACRO ; Конец макроопределения

CSEG ; Начало программного сегмента
SUBI16 0x1234,r16,r17 ; Вычесть 0x1234 из r17:r16

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

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

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

совместно с директивой для получения листингов отдельных частей

исходных файлов

Синтаксис:
.NOLIST

Пример:
.NOLIST ; Отключить генерацию листинга
.INCLUDE "macro.inc" ; Вложенные файлы не будут
.INCLUDE "const.def" ; отображены в листинге
.LIST ; Включить генерацию листинга

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

Директива ORG устанавливает счётчик положения равным заданной величине, которая передаётся как параметр. Для сегмента данных она устанавливает счётчик положения в

SRAM (ОЗУ), для сегмента программ это программный счётчик, а для сегмента EEPROM это положение в EEPROM. Если директиве предшествует метка (в той же строке) то

метка размещается по адресу указанному в параметре директивы. Перед началом компиляции программный счётчик и счётчик EEPROM равны нулю, а счётчик ОЗУ равен 32

(поскольку адреса 0-31 заняты регистрами). Обратите внимание что для ОЗУ и EEPROM используются побайтные счётчики а для программного сегмента – пословный.

Синтаксис:
.ORG выражение

Пример:
.DSEG ; Начало сегмента данных

ORG 0x37 ; Установить адрес SRAM равным 0x37
variable: .BYTE 1 ; Зарезервировать байт по адресу 0x37H

CSEG
.ORG 0x10 ; Установить программный счётчик равным 0x10
mov r0,r1 ; Данная команда будет размещена по адресу 0x10

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

Директива SET присваивает имени некоторое значение. Это имя позднее может быть использовано в выражениях. Причем в отличии от директивы

href="#EQU - Set a symbol equal to an expression">EQU

значение имени может быть изменено другой директивой SET.

Синтаксис:
.SET имя = выражение

Пример:
.SET io_offset = 0x23
.SET porta = io_offset + 2

CSEG ; Начало кодового сегмента
clr r2 ; Очистить регистр 2

Напомним, что директивы (псевдооператоры) - это инструкции ассемблеру, они обрабатываются только при ассемблировании (трансляции) программы. Приведем некоторые из часто используемых директив.

Директивы определения идентификаторов

Присваивают идентификатору с данным именем некоторое текстовое или числовое значение (выражение). Формат директив:

имя EQU текст

имя = числовое значение (выражение)

Разница между псевдооператорами EQU и =:

l EQU - присваивает значение постоянно (изменять нельзя), текст может быть символьным, числовым или смешанным выражением, определяющим константу, адрес, другое символьное имя, метку и т.д.;

l = - выполняет текущее присваивание (значение может быть переназначено, но только при трансляции, естественно); присваивает только числовое выражение, содержащее простые математические преобразования, которые при трансляции и будут выполнены (например: const + 1, 15H*4, 3*12/4 и т.п.).

Директивы определения данных

Используются для идентификации переменных и полей памяти. Формат директивы

[имя] D* выражение [,выражение] [,...].

Ключевые слова D* могут быть следующими:

l DB - определить байт (1 байт);

l DW - определить слово (2 байта);

l DD - определить двойное слово (4 байта);

l DQ - определить 8 байтов;

l DT- определить 10 байтов.

Рассматриваемые директивы объявляют переменную (имя) или присваивают полям (ячейкам) памяти начальные значения; резервируют в памяти (с более поздним присвоением значения) один или несколько байтов - DB, слов - DW, двойных слов - DD и т.д.

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

l константой:
const DB 56; const DW 1936; const DD 3FFH.
Обязательно следует учитывать диапазон и вместимость байта, слова и т.д.; так, для DB константа не может быть больше 255, для DW - 65 535, для DD -



l 65 535 2 – 1 = 4 294 967 295;

l вектором или таблицей:
table1 DB 30, 4, –15, 0, 0, 0, 56; table2 DW 1936, 3004, 56, 15.
В одном псевдооператоре допускается поместить строку до 132 позиций, причем вместо повторения одного и того же значения несколько раз (0 в table1) можно использовать псевдооператор DUP (duplicate - дублировать):
table1 DB 30, 4, –15, 3 dup(0), 56);

l строкой символов:
str1 DB "Вы ввели слишком большое число";
str2 DB "Bad command";
в псевдооператоре DB строка может содержать 255 символов, во всех остальных (DW, DD, DQ, DT) - только 2 символа.

l пустым полем:
pole1 DB ?; pole2 DW 12 dup(?),
при этом в элементы резервируемой памяти при загрузке программы ничего не записывается (заносится не 0, как, например, в директиве pole3 DW 5 dup(0), а просто резервируются ячейки памяти);

l символическим именем переменной:
var1 DW disp; var2 DD vector
(одна переменная определяется адресом другой, в директивах указывать offset не надо, поскольку имя переменной воспринимается как ее адрес). Такой вариант подходит, например, для хранения адресов ячеек памяти, меток, на которые допустимо ссылаться в программе (var1 DW disp), причем, если переменная находится в том же сегменте, что и ссылающаяся команда, то достаточно в качестве адреса указать только смещение (2 байта), то есть обойтись DW; если же переменная находится в другом сегменте, то необходимо указать и сегмент, и смещение (всего 4 байта), то есть следует использовать уже DD (var2 DD vector);

l простым выражением:
fn1 DB 80*3; fn2 DW (disp) + 256, вычисляемым, разумеется, только при трансляции программы.

Директивы определения сегментов и процедур

Сегмент определяется псевдооператорами:

имя_сег segment

имя_сег ends

В программе можно использовать 4 сегмента (по числу сегментных регистров) и для каждого указать соответствующий регистр сегмента псевдооператором ASSUME(assume - присвоить), например:

assume CS:codeseg, DS:dataseg, SS:stackseg

В директиве ASSUME регистр_сег:имя_сег [,..], в частности, ASSUME cs:codeseg, указывается, что для сегмента имя_сег (codeseg) выбран регистр регистр_сег (CS).

После директивы ASSUME следует явным образом загрузить адрес начала сегмента данных в регистр DS:

Процедура определяется псевдооператорами:

имя_процедуры proc ...

имя_процедуры endp

При определении процедуры после ключевого слова proc должен быть указан атрибут дистанции nearили far; если этого атрибута нет, то по умолчанию подразумевается near. Обычно процедура должна заканчиваться командой ret (return). Если процедура объявлена как near, то обращение к ней (call) должно производиться из того же сегмента; если procfar, то из любого сегмента (в этом случае командой ret из стека при возврате будет извлечено два слова: для IP и для CS).

Директивы управления трансляцией

Их несколько, наиболее часто используется END. Директива END отмечает конец программы и указывает ассемблеру, где завершить трансляцию. Формат: END [имя_программы].

Программирование процедур работы с устройствами ввода-вывода

Процедуры ввода-вывода в ПК выполняются, как правило, по прерываниям. Состав и использование основных видов прерываний и служебных функций DOS прерывания 21H рассмотрены в работах . Ниже мы кратко остановимся на вопросах программирования ввода-вывода лишь прерываний для отображения информации на дисплее и ввода с клавиатуры. Вопросы вывода информации на принтер и работы с файлами рассмотрены в работах .

Программирование работы с дисплеем

Задание режимов работы и обмен данными с дисплеем можно выполнять при прерываниях BIOS типа 10H, а вывод данных на дисплей и при прерываниях DOS типа 21H.

Видеооперации с прерыванием 21H DOS

l Вывод символа на экран дисплея: AH = 2 или AH = 6 и DL <> 0FFh. В регистре DL должен быть ASCII-код символа. Пример фрагмента программы (вывод символа «C»):

mov DL, 43H ; 43H - это ASCII-код символа C

l Вывод строки символов : AH = 9 (чаще всего используемая функция). В регистрах DS:DX должен находиться начальный адрес строки символов, которая обязана заканчиваться символом $. Пример фрагмента программы (отображение текста "вывод строки символов$"):

Text db "вывод строки символов$"

mov DX, offset text ; это адрес выводимой строки

l Ввод/вывод из файла через логический номер. Стандартные файловые логические номера определяют тип и устройство ввода-вывода:

l 0 - ввод с клавиатуры;

l 1 - вывод на экран дисплея;

l 2- вывод на экран сообщения об ошибке;

l 3- ввод-вывод на внешнее устройство;

l 4- вывод на печать.

Для ввода предназначена функция AH = 3Fh прерывания 21H, для вывода служит функция AH = 40h прерывания 21H. В регистр CX предварительно заносится число вводимых-выводимых байтов, а в регистр DX записывается начальный адрес поля памяти для ввода-вывода. В случае успешного завершения процедуры ввода-вывода обнуляется флаг переноса CF, а в регистре AX возвращается количество фактически переданных байтов. При неудачной операции флаг CF устанавливается в 1, а в регистр AX заносится код ошибки.

Приведенный ниже пример содержит фрагмент программы для вывода на экран текстового файла Text, содержащего 50 байтов.

text db 50 dup(" ")

mov BX, 1 ; указание устройства вывода

mov CX, 50 ;указание числа выводимых байт

mov DX, offset text ; указание начального адреса

; поля памяти, содержащего текст