Директивы ассемблера. Программирование в машинных кодах и на языке ассемблера. EQU – Присвоить имя выражению

Директивы ассемблера. Программирование в машинных кодах и на языке ассемблера. EQU – Присвоить имя выражению

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

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

Директива 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

Метки
Метка в языке ассемблера может содержать следующие символы:


Буквы: от A до Z и от a до z
Цифры: от 0 до 9
Спецсимволы: знак вопроса (?)
точка (.) (только первый символ)
знак "коммерческое эт" (@)
подчеркивание (_)
доллар ($)

Первым символом в метке должна быть буква или спецсимвол. Цифра не может быть первым символом метки, а символы $ и? иногда имеют специальные значения и обычно не рекомендуются к использованию. Большие и маленькие буквы по умолчанию не различаются, но различие можно включить, задав ту или иную опцию в командной строке ассемблера. Максимальная длина метки - 31 символ. Примеры меток: COUNT, PAGE25, $E10. Рекомендуется использовать описательные и смысловые метки. Имена регистров, например, AX, DI или AL являются зарезервированными и используются только для указания соответствующих регистров.
Если метка располагается перед командой процессора, сразу после нее всегда ставится символ «:» (двоеточие), который указывает ассемблеру, что надо создать переменную с этим именем, содержащую адрес текущей команды:
some_loop:

loopne some_loop
Когда метка стоит перед директивой ассемблера, она обычно оказывается одним из операндов этой директивы и двоеточие не ставится:

codesg segment
lodsw ; cчитать слово из строки,
cmp ax,7 ; если это 7 - выйти из цикла
codesg ends
Рассмотрим директивы, работающие напрямую с метками и их значениями: LABEL, EQU и =.

Директива LABEL

Метка label тип Директива LABEL определяет метку и задает ее тип. Тип может быть одним из: BYTE (байт), WORD (слово), DWORD (двойное слово), FWORD (6 байт), QWORD (учетверенное слово), TBYTE (10 байт), NEAR (ближняя метка), FAR (дальняя метка). Метка получает значение, равное адресу следующей команды или следующих данных, и тип, указанный явно. В зависимости от типа команда
mov метка,0 запишет в память байт (слово, двойное слово и т.д.), заполненный нулями, а команда
call метка выполнит ближний или дальний вызов подпрограммы.

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

Директива EQU

Директива EQU присваивает метке значение, которое определяется как результат целочисленного выражения в правой части. Результатом этого выражения может быть целое число, адрес или любая строка символов:
метка equ выражение

truth equ 1
message1 equ "Try again$"
var2 equ 4
cmp ax,truth ; cmp ax,1
db message1 ; db "Try again$"
mov ax,var2 ; mov ax, 4 Директива EQU чаще всего используется с целью введения параметров, общих для всей программы, аналогично команде #define препроцессора языка С.

Директива =

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

Каждый ассемблер предлагает целый набор специальных предопределенных меток — это может быть текущая дата (@date или??date), тип процессора (@cpu) или имя того или иного сегмента программы, но единственная предопределенная метка, поддерживаемая всеми рассматриваемыми нами ассемблерами, — $ . Она всегда соответствует текущему адресу. Например, команда

Jmp $

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

Чтобы получше уяснить все это дело я написал небольшую программку. Все тот же “Hello World”, но на новый лад:) Текст ниже:

Програ ассемблируется TASM и MASM, но EXE файлик, ассемблированный MASM на один байт больше. Замечаем что команду mov dx,offset msg, заменили на команду lea dx,msgb. LEA помещает адрес смещения указанных данных в DX, т.е. делает то же самое что и команда mov с offset. Рекомендую это посмотреть под отладчиком.



Смотрим внимательно листинги ассемблирования и находим разницу.



Интересно, что TASM ассемблировал команду LEA в данном случае как команду MOV (код операции BA), а MASM ассемблировал команду LEA в другой код операции - 8D16, что и увеличило размер программы на 1 байт. Почему он решил так сделать пока не знаю, но интересно было бы выяснить.

Здесь представлена информация по ассемблеру всей серии 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.

Одним из важнейших элементов этой части книги являются примеры программ в машинных кодах и на языке АССЕМБЛЕРа. В распечатках этих программ нам придется употреблять так

называемые ДИРЕКТИВЫ АССЕМБЛЕРа и сейчас, наверное, самое удобное время для того, чтобы дать представление о том, что это такое.

Мы рассмотрим следующие директивы: ORG, EQU, DEFB, DEFW, DEFM и END, но прежде чем начать их рассмотрение, надо твердо для себя понять:

1. Директивы АССЕМБЛЕРа не являются командами процессора Z8 0 и в этом смысле отношения к машинному коду Z8 0 не имеют.

2. АССЕМБЛЕР - это программа, которая переводит (транслирует) текст, написанный Вами в виде мнемоник в объектный код, являющийся машинным. И эти директивы АССЕМБЛЕРа - это некоторые команды ассемблирующей программе. Они не транслируются и в объектный код не войдут, но упростят Вам написание, и самое главное - чтение программы, записанной в мнемониках.

3. Программ-АССЕМБЛЕРов существует великое множество и каждая из них может иметь свои собственные директивы. Они могут иметь и одинаковые директивы, но предъявлять разные требования к их употреблению. Одним словом, конкретно способы использования директив АССЕМБЛЕРа Вам надо устанавливать по инструкции к ассемблирующей программе, которой Вы пользуетесь (напр. EDITAS, GENS 3, GENS 4, ZEUS и т.п.). И хотя стандартов не существует, тем не менее некоторые основополагающие понятия все же выделить можно, вот на них-то мы и остановимся.

3.1. Комментарии.

Мы начнем с самого простого - с комментариев. Они записываются после символа ";" (точка с запятой) .

Вам, конечно понятно, что все, что является комментариями, АССЕМБЛЕРом в машинный код не компилируется - это ни к чему. Они служат только для того, чтобы Вам было удобнее разбираться с листингом, который составил кто-то другой или Вы сами, но давным-давно.

Например:

10 60001 LD E,A 2 0

Как видите, строка может

; Загрузили в регистр E содер-; жимое аккумулятора. ; Уменьшили его на единицу.

остоять только из комментария.

Метки.

Метки значительно упрощают написание программ в мнемониках АССЕМБЛЕРа. В операциях перехода JP, JR, DJNZ, вызова подпрограмм CALL Вы можете не указывать адрес, в который Вы хотите совершить переход, а вместо него подставить метку. С другой стороны, когда будете писать команды для этого адреса, подставите метку и там, Например:

10 60001 BEGIN LD B,0 4

20 60003 AGAIN INC HL

40 60005 DJNZ, AGAIN

3.2.

250 260 270

60110 60111 60113

LD A,(HL) CP 80H JR NZ,BEGIN

Как видите, очень удобно. Сразу видно, что из строки 40 возврат осуществляется к метке AGAIN, если регистр B не достиг нуля. Из строки 270 возврат осуществляется к метке BEGIN.

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

При компиляции ассемблирующая программа сама подсчитает величины необходимых смещений в командах процессора и подставит их вместо меток. Так, например, в строке 40 вместо DJNZ AGAIN в объектный код пойдет DJNZ FCH, что то же самое.

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

Например, Вам в Вашей программе неоднократно приходится вызывать процедуры ПЗУ, скажем CLEAR (1EACH=7 8 52) и OUT-LINE (1856H=6230) . Тогда в начале Вашей программы Вы задаете

например назвав их CLEAR

директивой

значения своим меткам, н

и OUT L.

CLEAR

EQU 7 8 52

OUT L

EQU 62 3 0

LABEL

EQU 60016

выз

ываете эти

процедуры или

по метке.

60001

LD HL, (LABEL)

60004

LD BC, 0008

60007

LD DE, (04 52)

60010

CALL CLEAR

60013

CALL OUT L

60016

Сразу

должны Вас

предупредить,

примеры

с точки зрения

программной

примеры того, как используются те или иные директивы АССЕМБЛЕРа и если Вам нужен в примерах реальный смысл, то Вы его получите чуть позже, в последующих главах, где мы будем разбирать практические приемы программирования.

Давайте еще раз взглянем на предыдущий пример. В строке 30 мы засылаем в регистровую пару HL то, что содержится в адресе, на который указывает метка LABEL, а она, согласно директиве EQU указывает на адрес 60016.

Итак, в ячейках 60016 и 60017 содержатся некоторые данные, которые впоследствии могут использоваться программой. Эти данные Вы можете заслать в ячейки сами перед компиляцией. И совсем не надо для этого привлекать машинный код. Первоначальные значения в ячейках памяти Вы можете выставить с помощью директив DEFB, DEFW и DEFM.

DEFB - DEFINE BYTE - задать байт.

DEFW - DEFINE WORD - задать "слово" ("слово" - это два последовательно расположенных байта. Обычно это адрес.) DEFM - DEFINE MESSAGE - задать сообщение (это несколько подряд идущих байтов) . Обычно ассемблирующие программы накладывают ограничение на то, сколько байтов можно задать одной директивой DEFM, скажем не более пяти. Но Вас это не должно волновать. Если Вы хотите задать длинное сообщение, то можете ставить подряд столько строк DEFM, сколько хотите.

Итак, DEFB задает один одиночный байт (0...255) , DEFW -два подряд идущих байта (0...65535), а DEFM - группу подряд идущих байтов - текстовое сообщение, числовая таблица и т. п.

В нашем предыдущем примере, если мы хотим хранить в адресе 60016 и 60017 некоторое двухбайтное число, строку 80 следовало бы записать, например так:

80 60016 DEFW 5C92H

90 60018

Предположим, Вы хотите начиная с адреса 60135 хранить слово "Spectrum".

Код буквы "S" Код буквы "p" "e" "c" "t" " r "

"u" "m"

60135

60136

60137

60138

60139

60140

60141

60142

53H 7 0H 65H 63H 7 4H 72H 75H 6DH

DEFB DEFB DEFB DEFB DEFB DEFB DEFB DEFB

можете его задать парами байтов:

Но проще и правильнее задать его как сообщение:

60135 DEFM 5370656374 ; "Spect"

60140 DEFM 72756D ; "rum"

Есть особый случай при программировании на АССЕМБЛЕРе, когда текст программы тоже приходится вводить через DEFB или DEFM. Это случай, когда Вы пишете программу для встроенного калькулятора. Ведь ассемблирующая программа может перевести в машинный код мнемоники АССЕМБЛЕРа, но она ничего не знает о кодах калькулятора и не знает его мнемоник. Код калькулятора -это внутреннее "Синклеровское" дело, его интерпретацией

занимаются программы, размещенные в ПЗУ и к процессору и к его командам код калькулятора не имеет никакого отношения. Посему ввести команды калькулятору в ассемблирующую программу Вам удастся только как последовательность независимых байтов, т. е. через DEFB или DEFM.

Мы с Вами в первой части книги употребляли мнемонические обозначения команд калькулятора, типа add, stk_data s_lt и т. п., и писали их с маленькой буквы в отличие от команд процессора. Но делали это ранее и будем делать впредь только ради понимания и удобства записи. Программа-АССЕМБЛЕР таких мнемоник не знает, их нет в ее словаре.

Итак, с помощью DEFB, DEFW и DEFM задают начальные значения программным переменным, вводят в программу таблицы, сообщения и любые прочие последовательности данных, даже

графику, а также такие кодовые последовательности, которые ассемблирующая программа не понимает, как команды АССЕМБЛЕРа.

3.5. Директивы ORG, END.

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

Вы обратили внимание на то, что в вышеприведенных примерах мы слева писали столбец адресов, в которых будут размещаться те или иные команды. Так вот, этого при программировании на АСЕМБЛЕРе делать не надо. Достаточно в самом начале дать директиву

10 ORG 63000

и далее ассемблирующая программа сама рассчитает в какой ячейке памяти будет находиться та или иная команда. Это очень упрощает процесс программирования. А если Вы внесете изменения в готовый текст, АССЕМБЛЕР сам подправит все адреса.

Директива END отмечает конец программы. Если после него что-то еще и будет стоять, то АССЕМБЛЕР при компиляции это проигнорирует.

Вот пожалуй и все, что для начала стоит знать о директивах АССЕМБЛЕРа. Это не все директивы, какие могут встретиться в жизни, да и правила их использования для разных АССЕМБЛЕРов -разные, но по большому счету этот минимум удовлетворит 90 процентов Ваших потребностей в информации, а остальное Вы должны почерпнуть из инструкции к тому АССЕМБЛЕРу, с которым работаете.



© 2024 beasthackerz.ru - Браузеры. Аудио. Жесткий диск. Программы. Локальная сеть. Windows