Программирование на языке Ассемблер. Учебное пособие
.pdf
Рис. 6. Наблюдение за значениями переменных
Переменная может быть просмотрена в любой числовой системе:
HEX – шестнадцатеричной (основа 16);
BIN – двоичной (основа 2);
OCT – восьмеричной (основа 8);
SIGNED – десятичной со знаком (основа 10);
UNSIGNED – десятичной без знака (основа 10);
CHAR – коды ASCII-символов (всего 256 символов, некоторые символы невидимы).
Можно редактировать переменные, когда программа выполняется, двойным нажатием кнопки мышки по переменной, или выбрав ее и нажав кнопку [Edit].
Можно вводить числа в любой системе, шестнадцатеричные цифры должны иметь суффикс «h», двоичные – суффикс «b», восьмеричные – суффикс «o», десятичные цифры не требуют суффикса. Строка может быть введена следующим способом:
'hello world', 0
(эта строка заканчивается нулем).
21
Массив может быть введен следующим способом:
1, 2, 3, 4, 5
(массив может быть массивом байтов или слов, это зависит от того, выбран BYTE или WORD для введенной переменной).
Выражения преобразуются автоматически. Например, если введено следующее выражение:
5 + 2
оно будет преобразовано в 7.
22
4. ПРЕРЫВАНИЯ
Прерывания можно рассматривать как номер функции. Эти функции делают программирование более легким – вместо написания дополнительного кода, можно просто вызвать прерывание, которое выполнит необходимую функцию. Существуют также функции прерываний, которые работают с дисками и другим «железом». Такие функции называются
программными прерываниями. Прерывания могут быть также вызваны различными устройствами, такие прерывания называются аппаратными прерываниями.
Чтобы выполнить программное прерывание, исполь-
зуют команду INT, которая имеет очень простой синтаксис:
INT значение
значение может быть числом в диапазоне от 0 до 255 (или от 0 до 0FFh), обычно используются шестнадцатеричные числа.
Можно предположить, что существует всего 256 функций, но это не так. Каждое прерывание может иметь подфункции. Чтобы определить подфункцию, в регистр AH нужно записать ее номер перед вызовом прерывания.
Каждое прерывание может иметь до 256 подфункций (таким образом получаем 256 256 = 65536 функций). В основном используется регистр AH, но иногда могут использоваться и другие регистры. Обычно другие регистры используются для записи параметров и данных подфункции.
Следующий пример использует прерывание INT 10h
иподфункцию 0Eh, чтобы напечатать сообщение «Hello!». Эта функция выводит символ на экран, перемещая курсор
ипрокручивая экран по необходимости.
#MAKE_COM# ; инструкция компилятора для ; создания СОМ-файла.
ORG 100h
;Подфункция, которую мы используем
;не изменяет регистр АН после завершения,
23
; так что мы можем использовать его только один раз MOV AH, 0Eh ; выбор подфункции
;Подфункция INT 10h / 0Eh принимает
;в качестве параметра ASCII-код символа,
;который нужно записывать в регистр AL
MOV AL, 'H' |
; ASCII-код: 72 |
INT 10h |
; напечатать его |
MOV AL, 'e' |
; ASCII-код: 101 |
INT 10h |
; напечатать его |
MOV AL, 'l' |
; ASCII-код: 108 |
INT 10h |
; напечатать его |
MOV AL, 'l' |
; ASCII-код: 108 |
INT 10h |
; напечатать его |
MOV AL, 'o' |
; ASCII-код: 111 |
INT 10h |
; напечатать его |
MOV AL, '!' |
; ASCII-код: 33 |
INT 10h |
; напечатать его |
RET |
; вернуться в операционную систему |
Введите эту программу в редактор кода Emu8086 и нажмите кнопку [Compile and Emulate]. Запустите ее.
24
5. БИБЛИОТЕКА ОБЩИХ ФУНКЦИЙ – EMU8086.INC
Чтобы облегчить программирование, имеются несколько общих функций, которые можно включать в программу. Чтобы использовать в программе функции, определенные в другом файле, необходимо применить директиву INCLUDE, за которой следует имя файла. Компилятор автоматически найдет файл в той же папке, где размещен файл с исходным кодом программы, а если там этого файла не окажется, то поиск будет продолжен в папке Inc.
Чтобы использовать какие-либо функции в emu8086.inc, необходимо добавить следующую строку в исходном файле программы:
include 'emu8086.inc'
Еmu8086.inc определяет следующие макросы:
PUTC char – макрос с одним параметром, печатает ASCII-символ в текущей позиции курсора;
GOTOXY col, row – макрос с двумя параметрами, устанавливает позицию курсора;
PRINT string – макрос с одним параметром, печатает строку;
PRINTN string – макрос с одним параметром, печатает строку. Это то же самое, что и PRINT, но автоматически добавляется «перевод каретки» в конце;
CURSOROFF – скрывает текстовый курсор;
CURSORON – показывает текстовый курсор.
Чтобы использовать какой-либо из вышеописанных макросов, необходимо напечатать его имя в тексте программы и, если необходимо, параметры. Например:
include emu8086.inc ORG 100h
PRINT 'Hello World!' GOTOXY 10, 5
25
PUTC 65 |
; 65 – это ASCII-код для буквы 'A' |
PUTC 'B' |
|
RET |
; вернуться в операционную систему |
END |
; директива для окончания компиляции |
Когда компилятор обрабатывает исходный код, он ищет файл emu8086.inc для объявленных макросов и заменяет имя макроса реальным кодом. Вообще макросы – это относительно небольшие участки кода, частое использование макросов может сделать программу (исполняемый файл) слишком большой (для оптимизации размера лучше использовать процедуры).
Emu8086.inc также определяет следующие процедуры. PRINT_STRING – процедура для печати строки с нулевым окончанием с текущей позиции курсора. Получает адрес строки в регистре DS:SI. Чтобы использовать эту процедуру, следует
объявить: DEFINE_PRINT_STRING перед директивой END. PTHIS – процедура для печати строки с нулевым окон-
чанием с текущей позиции курсора (как и PRINT_STRING), но получает адрес из стека. Строка с нулевым окончанием должна быть определена только после команды CALL. Например:
CALL PTHIS
db 'Hello World!', 0
Чтобы использовать эту процедуру, следует объявить:
DEFINE_PTHIS перед директивой END.
GET_STRING – процедура для получения строки с нулевым окончанием от пользователя. Принятая строка записана в буфер, адрес которого указан в DS:DI, размер буфера должен быть в DX. Процедура завершает ввод, если нажата клавиша «Enter». Чтобы использовать эту процедуру, следует объявить: DEFINE_GET_STRING перед директивой END.
CLEAR_SCREEN – процедура для очистки экрана (выполняет полную прокрутку экрана и устанавливает курсор в его верхней части) Чтобы использовать эту процедуру, следует объявить: DEFINE_CLEAR_SCREEN перед директивой END.
26
SCAN_NUM – процедура, которая получает многозначное число со знаком с клавиатуры и записывает результат в регистр CX. Чтобы использовать эту процедуру, следует объявить: DEFINE_SCAN_NUM перед директивой END.
PRINT_NUM – процедура, которая печатает число со знаком, которое находится в регистре AX. Чтобы использовать эту процедуру, следует объявить: DEFINE_PRINT_NUM перед директивой END.
PRINT_NUM_UNS – процедура, которая печатает число без знака из регистра AX. Чтобы использовать эту процедуру, следует объявить: DEFINE_PRINT_NUM_UNS перед директивой END.
Чтобы использовать какую-либо из вышеописанных процедур, сначала необходимо объявить функцию в нижней части файла (но перед END!), а затем использовать команду CALL, за которой следует имя процедуры. Пример:
include 'emu8086.inc'
ORG 100h |
|
|
LEA SI, |
msg1 |
; попросить ввести число |
CALL print_string |
||
CALL scan_num |
; получить число в CX |
|
MOV AX, |
CX |
; копировать число в AX |
; напечатать следующие строки: CALL pthis
DB 13, 10, 'You have entered: ', 0
CALL print_num |
; |
напечатать число из AX |
RET |
; вернуться в операционную систему |
|
msg1 DB 'Enter the number: ', 0 DEFINE_SCAN_NUM DEFINE_PRINT_STRING DEFINE_PRINT_NUM
DEFINE_PRINT_NUM_UNS ; требуется для print_num
DEFINE_PTHIS |
|
END |
; директива окончания компиляции |
27
Сначала компилятор обрабатывает объявления (это просто обычные макросы, которые рассматриваются до процедур). Когда компилятор получает команду CALL, он заменяет имя процедуры адресом кода, где объявлена процедура. Когда выполнится команда CALL, то управление будет передано процедуре. Это очень удобно: даже если вызов в коде одной и той же процедуры происходит 100 раз, то размер исполняемого файла будет оставаться относительно небольшим.
28
6. АРИФМЕТИЧЕСКИЕ И ЛОГИЧЕСКИЕ КОМАНДЫ
Большинство арифметических и логических команд влияют на регистр состояния процессора (или Флаги) (рис. 7).
Рис. 7. Содержимое регистра
В данном регистре 16 бит. Каждый бит называется флагом и может принимать значение 1 или 0.
Carry Flag (CF) – перенос – этот флаг устанавливается в 1, когда случается беззнаковое переполнение. Например, при увеличении байт 255 + 1 (результат не помещается в диапазоне 0...255). Если переполнение не происходит, этот флаг установлен в 0.
Zero Flag (ZF) – ноль – устанавливается в 1, если результат равен нулю. Если результат не нулевой, то этот флаг устанавливается в 0.
Sign Flag (SF) – знак – установлен в 1, если резуль-
тат – отрицательное число. Если результат положительный,
то этот флаг устанавливается в 0. Обычно этот флаг принимает значение старшего значащего бита.
Overflow Flag (OF) – переполнение – устанавлива-
ется в 1, если случается переполнение при арифметических операциях со знаком. Например, если вы увеличили байт 100 + 50 (результат не помещается в диапазоне -128...127).
29
Parity Flag (PF) – контроль четности – этот флаг устанавливается в 1, если в младших 8-битовых данных четное число. Если число нечетное, то этот бит установлен в 0. Даже если результат – это слово, то анализируются только 8 младших бит!
Auxiliary Flag (AF) – внешний перенос – установ-
лен в 1, если случилось переполнение без знака младших 4 битов (т. е. перенос из 3-го бита).
Interrupt enable Flag (IF) – прерывание – если этот флаг установлен в 1, то процессор реагирует на прерывание от внешних устройств.
Direction Flag (DF) – направление – этот флаг ис-
пользуется некоторыми командами для обработки цепочки данных. Если флаг установлен в 0 – обработка происходит в прямом направлении, если 1 – в обратном.
Имеются три группы команд.
Первая группа: ADD, SUB,CMP, AND, TEST, OR, XOR.
Эти типы операндов поддерживаются:
REG, memory memory, REG REG, REG
memory, immediate REG, immediate
REG: AX, BX, CX, DX, AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.
memory: [BX], [BX+SI+7], переменная, и т. п. immediate: 5, -24, 3Fh, 10001101b, и т. п.
После операции между операндами результат всегда записывается в первый операнд. Команды CMP и TEST воздействуют только на флаги и не записывают результат (эта команда используется для принятия решения во время выполнения программы).
Этикомандывлияюттольконафлаги:CF, ZF, SF,OF,PF, AF.
30
