Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

epd627

.pdf
Скачиваний:
22
Добавлен:
02.05.2015
Размер:
816.97 Кб
Скачать

предпочтительным методом является выполнение функции с номером 4Ch. Именно эта функция и используется в приведенном примере.

stacksg segment para ‘Stack’

 

db

100h

 

; стек объемом 256 байтов

stacksg ends

 

 

datasg segment para ‘Data’

; начало сегмента данных

datasg ends

 

 

codesg segment para ‘Code’

; начало сегмента кода

. . .

 

 

EhcoLoop:

 

 

mov

ah,1

; функция DOS ввода с клавиатуры

int

21h

; получить следующую клавишу

cmp

al,13

; это клавиша enter?

jz EchoDone

; да, выполняем эхоотображение

mov

dl,al

; поместить символ в dl

mov

ah,2

; функция DOS вывода на экран

int

21h

; вывести на экран символ

jmp

EchoLoop

; отобразить следующий символ

EchoDone:

 

 

mov

ah,4ch

; функция DOS завершения программы

int

21h

; завершить программу

. . .

codesg ends end

4.46. Базовая система ввода-вывода

Если нет нужной функции DOS, обратитесь к базовой системе вводавывода IBM PC BIOS. В отличие от DOS и прикладных программ BIOS хранится в памяти, доступной только по чтению (ROM или ПЗУ).

BIOS является программным обеспечением нижнего уровня. Даже DOS использует для управления аппаратурой функции BIOS. Аналогично DOS BIOS позволяет "скрыть" различия между различными компьютерами

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

ит.д. [1, с. 151165].

Программное обеспечение коммуникаций управляет портом IBM PC с помощью инструкций in и out, поскольку ни DOS, ни BIOS не предусматривают адекватной поддержки. Подробнее см. уч. пос., ч.8.

4.47. Выражения

51

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

MemVar db 0

 

dw 0

 

dw 0

 

dw 0

 

NextVardb ?

 

. . .

 

mov

ax,seg MemVar

;загрузки в ds постоянного значения

mov

ds,ax

; сегмента, в котором находится MemVar

mov

bx,offset MemVar +(1+ (3*2))

mov

byte ptr [bx],1

 

Вэтой программе используется сложное выражение, включающее в себя операции *, +, и offset, при вычислении которого получается значение offset MemVar+7, которое представляет собой адрес NextVar. Наконец, для выбора байтовой операции при сохранении константы 1 в ячейке, на которую указывает регистр bx (что представляет собой NextVar), используется операция byte ptr.

Примечание. При вычислении всех выражений должно получаться значение-константа.

Здесь offset MemVar – это значение-константа, представляющее собой смещение переменной MemVar в ее сегменте (например, смещение этой переменной от начала сегмента данных может быть равным 5000). Сохраненное в переменной MemVar значение (в приведенном выше примере оно равно нулю) может изменяться, сама переменная MemVar, конечно, никуда не перемещается.

Так как значения-константы точно известны, ассемблер может вычислять состоящие из постоянных значений выражения так же, как он ассемблирует исходный текст программы (т.е. исходный код). Для ассемблера выражение offset MemVar + 7 совершенно аналогично выражению 5000 + 7. Поскольку все элементы выражения неизменяемы и определены во время ассемблирования, выражение можно свести к одному значению - константе.

Ввыражениях могут использоваться следующие операции:

(), size, offset, ptr, *, /, +, - (бинарные)

Другие операции, которые могут использоваться в выражениях (LENGTH, MASK, WIDTH, . (селектор элемента структуры), HIGH,

52

LOW, : (переопределение сегмента), SEG, THIS, .TYPE, LARGE, SHORT, SMALL) *, /, shl, shr, +, - (бинарные), eq, ge, gt, le, lt, ne, not, and, or, xor (см. уч. пос., ч.6).

53

4.48. Биты, байты, слова, двойные и учетверенные слова

Как было отмечено выше (см. п. 4.5), основной единицей памяти компьютера является бит. В бите может храниться значение 0 или 1. Байт состоит из 8 битов. В каждом из 8-разрядных регистров процессора (al, ah, bl, cl, ch, dl и dh) и в каждой из более чем 1 000 000 адресуемых ячеек памяти хранится ровно 1 байт. (Если быть точным, то количество адресуемых ячеек равно 220, т.е. 1 048 576).

Набор символов компьютера включает в себя строчные и прописные символы, цифры от 0 до 9, специальные графические символы, научные и специальные символы, а также различные знаки пунктуации и прочие символы – всего 256 символов. Набор символов построен таким образом, что в 1 байте хранится 1 символ.

Байт – это наименьшая единица адресации процессора. В нем может храниться один символ, одно беззнаковое значение от 0 до 255 или одно значение со знаком в диапазоне от -128 до +127. Байт не подходит для хранения значений с плавающей точкой и указателей на память.

Следующая по величине единица памяти процессора – это слово. Оно вдвое превосходит по размеру байт (содержит 16 битов). Фактически слово хранится в памяти в виде двух последовательных байтовых ячеек. Адресное пространство процессора можно рассматривать как немногим более 500 000 слов. В каждом из 16-разрядных регистров (регистр ax, bx, cx, dx и др.) также хранится одно слово.

Число 65 535 представляет собой максимальную величину целого без знака, хранящегося в слове. Целые со знаком могут принимать значения в диапазоне от -32 768 до +32 767.

Слова могут адресоваться по любому смещению в данном сегменте, значения размером в слово можно использовать в качестве указателей памяти. Например, регистры bx, bp, si и di размером в слово используются как указатели на память.

Значения, хранимые в виде 32-битовых (4-байтовых) элементов, называются двойными словами. Процессор 8086 не может непосредственно работать с 32-битовыми целыми значениями, но выполнять 32-разрядные арифметические операции (с помощью двух последовательных 16-разрядных операций) можно с помощью таких инструкций, как adc и sbb. В двойных словах беззнаковые целые могут принимать значения в диапазоне от 0 до 4 294 967 295, а целые со знаком – в диапазоне от -2 147 483 648 до +2 147 483 647.

Учетверенными словами называются 64-битовые значения (восемь байтов). В процессоре 8086 встроенная поддержка учетверенных слов отсутствует. Процессор 8086 не может непосредственно работать с 64-

54

битовыми целыми значениями, но выполнять 64-разрядные арифметические операции (с помощью четырех последовательных 16разрядных операций) можно с помощью таких инструкций, как adc и sbb.

Ассемблер поддерживает еще один тип данных – элемент данных длиной 10 байтов. Этот 10-байтовый элемент данных может, например, использоваться для хранения суммы учетверенных слов.

Значения размером в слово, двойное или учетверенное слово в памяти хранятся таким образом, что младший байт следует первым. То есть если значение размером в слово хранится по адресу 0, то биты 7-0 значения записаны по адресу 0, а биты 15-8по адресу 1.

Аналогично, если значение размером в двойное слово хранится по адресу 5, то биты 7-0 хранятся по адресу 5, биты 15-8 хранятся по адресу 6, биты 23-16 – по адресу 7, а биты 31-24 – по адресу 8.

4.49. Представление числовых значений

Легче всего пользоваться десятичными значениями: mov cx,100 ; установить счетчик в значение 100.

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

Можно указать ассемблеру, что число выражено в двоичном виде, если поместить в конце числа букву b (при этом число должно состоять только из 0 и 1, поскольку это единственные две цифры, допустимые в двоичном представлении). Например, десятичное значение 100 выражается в двоичном виде как 1100100b.

Последняя инструкция с операндами в двоичном представлении будет иметь вид:

mov cx,1100100b ; установить счетчик в значение 100 В восьмеричном виде последний пример принимает вид:

mov cx,144o ; установить счетчик в значение 100 mov cx,144q ; установить счетчик в значение 100

Суффиксы o и q указывают на восьмеричную запись. В шестнадцатеричном виде последний пример принимает вид:

mov cx,64h ; установить счетчик в значение 100 Шестнадцатеричные числа обозначаются суффиксом h. Кроме того,

шестнадцатеричные числа должны начинаться с одной из цифр 0-9, так как шестнадцатеричное число типа bad4h может ошибочно интерпретироваться как метка. Пример, в котором используется как число

0bad4h, так и метка bad4h: datasg segment para ‘Data’

bad4h dw 0

;метка bad4h

 

55

datasg ends

codesg segment para ‘Code’

mov ax,0bad4h ; загрузить в ax шестнадцатеричную константу

. . . ; (первый 0 показывает, что это константа) mov ax,bad4h ; загрузить ax из переменной в памяти bad4h

; (отсутствие 0 в качестве первого символа показывает, что это метка)

. . .

codesg ends

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

Числа с плавающей точкой могут обозначаться двумя способами (см.

уч. пос., ч.4).

Чтобы показать, что число является десятичным, в качестве суффикса можно использовать букву d. Наконец, могут использоваться символьные константы, при этом символы заключаются в одиночные или двойные кавычки. Значением символа является его значение кода ASCII. Например, все следующие строки загружают в регистр al значение кода ASCII

символа А [1, с. 559].

 

mov

al,65

; 65 = 41h

mov

al,41h

 

mov

al,'A'

; ASCII код символа А = 41h

mov

al,"A"

; ASCII код символа А = 41h

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

4.50. Инициализированные данные

Директивы определения данных db, dw, dd, dq и dt позволяют определить переменные в памяти различного размера: один байт (db), два байта, т.е. одно слово (dw), четыре байта, т.е. двойное слово (dd), восемь байтов, т.е. одно учетверенное слово (dq) и десять байтов (dt).

Например:

datasg segment para ‘Data’

ByteVar db 'Z'

; 1

байт

WordVar dw 101b

; 2

байта (1 слово)

DwordVardd 2BFh

; 4

байта (1 двойное слово)

QwordVar dq 307o

; 8

байтов (1 учетверенное слово)

TwordVardt 100

; 10 байтов

datasg ends

codesg segment para ‘Code’

. . .

mov ah,2 ; функция DOS вывода на дисплей

56

mov dl,ByteVar ; символ, который нужно вывести на экран int 21h

mov ax,WordVar

. . .

add word ptr DwordVar,ax adc word ptr DwordVar+2,dx

. . .

codesg ends

Здесь определяются пять переменных памяти и показывается, как некоторые из таких переменных можно использовать.

4.51.Инициализация массивов

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

SampleArrray dw 0, 1, 2, 3, 4

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

Если нужно определить массив, который слишком велик и не вмещается на одной строке, нужно добавить несколько строк. Метку в директиве определения данных указывать необязательно. Например, по директивам:

SquareArray dd 0, 1, 4, 9, 16 dd 25, 36, 49, 64, 81

dd 100, 121, 144, 169, 196

создается массив элементов размером в двойное слово с именем SquareArray, состоящий из квадратов первых 15 целых чисел.

Ассемблер позволяет определить блок памяти, инициализированный указанным значением, с помощью операции dup. Например,

BlankArraydw 100h dup (0)

Здесь создается массив BlankArray, состоящий из 256 слов (подругому: 100h), инициализированных значением 0. Аналогично директива:

ArrayOf_A db 92 dup ('A')

создает массив из 92 байтов, и каждый инициализирован символом A.

4.52.Инициализация строк символов

Строку символов можно определить следующим образом:

Stringdb 'A', 'B', 'C', 'D'

Предусмотрена также удобная сокращенная форма:

String db 'ABCD'

Чтобы переместиться к левому краю следующей строки, нужно вывести символы "возврат каретки/перевод строки". Например:

57

stacksg segment para ‘Stack’ db 256 dup (0)

stacksg ends

datasg segment para ‘Data’

String1 db

'Line1','$'

 

String2 db

'Line2','$'

 

String3 db

'Line3','$'

 

datasg ends

 

codesg segment para ‘Code’

ProgramStart:

 

mov ax,datasg

 

mov ds,ax

 

mov ah,9

 

; функция DOS печати строки

mov dx,offset String1

; печатаемая строка

int 21h

 

; вызвать DOS для печати строки

mov dx, offset String2

; печатаемая строка

int 21h

 

; вызвать DOS для печати строки

mov dx, offset String3

; печатаемая строка

int 21h

 

; вызвать DOS для печати строки

mov ah,4ch

; функция DOS завершения программы

int 21h codesg ends

end ProgramStart

Программа печатает следующее:

Line1Line2Line3

Однако если в конце каждой строки добавить символы "возврат каретки/перевод строки":

String1 db 'Line1',0dh,0ah,'$' String2 db 'Line2',0dh,0ah,'$' String3 db 'Line3',0dh,0ah,'$'

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

Line1

Line2

Line3

4.53. Инициализация выражений и меток

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

58

Можно также использовать: выражения:

TestVar dw ((924/2)+1); TestVar инициализируется значением 463

и метки:

datasg segment para ‘Data’

db 1,2,3,4,5,6,7,8,9,10,10,9,8,7,6,5,4,3,2,1

Buffer dw 16 dup (0) ; область памяти из 16-ти нулевых слов

BufferPointer dw Buffer datasg ends

Начальное значение BufferPointer представляет собой смещение Buffer в сегменте datasg, а не значение 0, которое хранится в переменной Buffer. В результате этого и инструкция:

mov ax,offset Buffer

и инструкция:

mov ax,BufferPointer

загрузят в регистр ax одно и то же значение (смещение переменной Buffer, которое в приведенном выше примере равно 20, т.к. в сегменте данных перед областью данных с меткой Buffer располагается 20 байтов данных).

В выражениях определения данных допускается использовать метки. Например, переменная WordArrayLength инициализируется значением длины (в байтах) WordArray:

datasg segment para ‘Data’

WordArray dw 50 dup (0); массив из 50-ти нулевых слов

WordArrayEnd label word

WordArrayLength dw (WordArrayEnd - WordArray);длина = 100 datasg ends

Если требуется вычислить длину переменной WordArray в словах, а не в байтах, это можно сделать, просто разделив длину в байтах на 2:

WordArrayLength dw (WordArrayEnd - WordArray) / 2

4.54. Неинициализированные данные

Иногда нет смысла присваивать переменной памяти начальное значение. Тогда применяют знак вопроса (?). Например:

KeyBuffer db 10 dup (?)

В данной строке резервируется 10 байтов памяти, начиная с метки KeyBuffer, но этим байтам не присваивается никакого конкретного значения.

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

59

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

4.55. Именованные ячейки памяти

Кроме присвоения имени ячейке памяти с помощью метки, предшествующей директиве определения данных (например, db), можно присваивать имя ячейке директивой label, которая позволяет определить имя метки и ее тип, не определяя при этом данные. Например, в предыдущем примере массив KeyBuffer можно определить так:

KeyBuffer label byte db 10 dup (?)

Типы меток, которые можно определить с помощью label, включают в себя: byte, word, dword, qword, tbyte, proc, near, far, unknown и др.

Типы byte (байт), word (слово), dword (двойное слово), qword (учетверенное слово) и tbyte (десять байтов) говорят сами за себя, определяя, соответственно, 1-, 2-, 4-, 8- и 10-байтовые элементы данных. Приведем пример инициализации переменной, как пары байтов, но обращения к ней, как к слову:

datasg segment para ‘Data’ WordVar label word

db 1,2 datasg ends

codesg segment para ‘Code’

. . .

mov ax,[WordVar]

. . .

Когда эта программа выполняется, в регистр al загружается 1 (первый байт WordVar), а в регистр ah – значение 2.

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

codesg segment para ‘Code’

. . .

FarLabel label far NearLabel label near

mov ax,1

. . .

jmp FarLabel

. . .

jmp NearLabel

. . .

60

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]