
- •Регістри загального призначення процесора 8086
- •Р егістри спеціального призначення процесора 8086
- •Набір інструкцій процесора
- •Xchg ах, bx ; Міняємо місцями вміст ах і bx
- •Визначення даних
- •Виклик функцій bios і операційної системи
- •Директиви segment, assume, end і .386
- •Приклад визначення сегменту:
- •X db ? ; байт пам'яті, початкове значення якого не визначено
- •Управління пам'яттю процесора
- •Типи адресації 8086
- •Типи адресації 80386
- •Контроль над програмним потоком
- •Команди переходу після зіставлення чисел з урахуванням знака:
Команди переходу після зіставлення чисел з урахуванням знака:
Команда |
Розшифровка |
Умова переходу |
Прапори |
Синоніми |
Антонім |
JG |
Jump if greater |
А > B |
SF=OF | ZF=0 |
JNLE |
JNG |
JNLE |
Jump if not lower or equal |
А не <= B |
SF=OF | ZF=0 |
JG |
JLE |
JGE |
Jump if greater or equal |
А >= B |
SF = |
JNL |
JNGE |
JNL |
Jump if not lower |
А не < B |
SF = |
JGE |
JL |
JL |
Jump if lower |
А < B |
SF != |
JNGE |
JNL |
JNGE |
Jump if not greater or equal |
А не >= B |
SF != |
JL |
JGE |
JLE |
Jump if lower or equal |
А <= B |
CF!=OF | ZF=1 |
JNG |
JNLE |
JNG |
Jump if not greater |
А не > B |
CF!=OF | ZF=1 |
JLE |
JG |
JE |
Jump if equal |
А = B |
ZF = 1 |
JZ |
JNE |
JNE |
Jump if not equal |
А не = B |
ZF = 0 |
JNZ |
JE |
В таблицях знак «|» означає «або», а «!» - «не».
Приклади роботи з умовними переходами:
CMP АХ, 4 ; Порівнюємо вміст АХ і 4
JB exit ; Якщо АХ менше 4, то переходимо по мітці
SUB BX, 10 ; віднімаємо 10 з BX
JZ lb1 ; якщо в результаті вийшов 0, то йдемо на lb1
JG lb2 ; якщо результат позитивний, то йдемо на lb2
Але необхідно враховувати, що мітка повинна знаходитися не далі 127 байтів від інструкції умовного переходу (в трансльованому коді) для 8086 або 32767 байтів для 80386. Якщо все ж таки ця ситуація відбулася, її можна вирішити за допомогою введення додаткової мітки. Наприклад, для мітки exit з попереднього фрагмента:
CMP АХ, 4 ; Порівнюємо вміст АХ і 4
JNB dop ; Замінюємо команду антонімом. Тепер, у випадку
; АХ >= 4, переходимо на додаткову мітку
JMP exit ; Якщо ж АХ менше 4, то переходимо на exit
dop: SUB BX, 10 ; віднімаємо 10 з BX
JZ lb1 ; якщо в результаті вийшов 0, то йдемо на lb1
JG lb2 ; якщо результат позитивний, то йдемо на lb2
За допомогою безумовних переходів в асемблерних програмах можна організовувати нескінченні цикли:
forever: ; мітка початку циклу
...
JMP forever ; перехід на початок
Очевидної користі в нескінченному циклі немає, набагато частіше використовують цикли з перевіркою умови виходу. Наприклад, цикл з послеусловием:
MOV АХ, 100 ; АХ використовуватиметься як лічильник повторів
beg: ; мітка початку циклу
...
DEC АХ ; віднімаємо від АХ одиницю
JNZ beg ; якщо АХ не нуль, то перехід на початок
Той же цикл, тільки з предусловием:
MOV АХ, 100 ; АХ використовуватиметься як лічильник повторів
beg: DEC АХ ; віднімаємо від АХ одиницю
JZ ex ; якщо АХ нуль, то перехід на кінець циклу
...
JMP beg ; безумовний перехід на початок
ex:
Як і в наведеному приклад, часто з'являється необхідність повторити цикл певна кількість раз. Для спрощення цієї процедури, в процесорі 8086 існує інструкція LOOP. Її синтаксис аналогічний команді умовного переходу.
LOOP <метка або відносний адрес>
Команда LOOP виконує дві операції: вона віднімає з регістра CX одиницю, і якщо після цього CX не рівний нулю, то переходить на вказану мітку. Тобто, ця команду можна вигідно застосувати для циклу з послеусловием з прикладу, тільки тепер як регістр-лічильника виступатиме CX:
MOV CX, 100 ; лічильник повторів
beg: ; мітка початку циклу
...
LOOP beg ; CX = CX-1. Якщо CX не нуль, то перехід на beg
Цикли можна широко використовувати для роботи з масивами даних. Наприклад, підрахуємо суму всіх елементів масиву:
DATA SEGMENT
А DW 1, 3, 6, 3, 7, 1, 0, 42, 3, 87 ; масив
DATA ENDS
CODE SEGMENT
...
MOV АХ, 0 ; АХ берегтиме суму
MOV CX, 10 ; лічильник повторів
MOV SI, offset А ; в SI покладемо зсув А щодо сегменту даних
beg: ADD АХ [SI] ; додамо до суми вміст пам'яті за адресою DS:SI
ADD SI, 2 ; перейдемо на наступний елемент масиву
LOOP beg ; CX = CX-1. Якщо CX не нуль, то перехід на beg
...
CODE ENDS
В процесорі 80386 програма ще більш спрощується, тільки тепер сума вважається з кінця масиву:
.386
DATA SEGMENT USE16
А DW 1, 3, 6, 3, 7, 1, 0, 42, 3, 87 ; масив
DATA ENDS
CODE SEGMENT USE16
...
MOV EAX, 0 ; EAX берегтиме суму
MOV ЕСX, 10 ; лічильник повторів
beg: ADD АХ, А[ECX*2-2] ; кожний елемент масиву займає 2 байти
LOOP beg ; ЕСX = ECX-1. Якщо ЕСX не нуль, то перехід на beg
...
CODE ENDS
В деяких версіях для обробки подібних програм слід використовувати команду TLINK/3.
Завдання на лабораторну роботу
Написати програму для процесора 80386, яка копіює рядок символів, що лежить в одному з сегментів, в масив двобайтових слів за певною адресою. В старші байти масиву слів записати номер свого варіанту. Відстежити роботу програми у відладчику.
Приклад виконання роботи
В наведеному приклад виконується копіювання трьох рядків. Перший рядок лежить в сегменті даних, друга – в сегменті стека, а третя – в сегменті коду після безумовного переходу. Використовуються цикли з послеусловием. Рядки копіюються за адресами 0b800h, 0b800h:160, 0b800h:320 відповідно.
.386
ASSUME CS:CODE, DS:DATA ; зв'язуємо сегментні регістри і сегменти
;-----------------------------------------------------------------------------
DATA SEGMENT USE16 сегмент даних
str1 DB 'Строка 1 '
DATA ENDS
;-----------------------------------------------------------------------------
STK SEGMENT USE16 STACK ; сегмент стека
str2 DB 'Строка 2 '
DB 100 dup (0) ; буфер для системного стека
STK ENDS
;-----------------------------------------------------------------------------
CODE SEGMENT USE16
start: MOV ах, 0B800h ; вкажемо в ES сегмент для висновку
MOV es, ах
MOV ах, DATA ; в DS - сегмент даних
MOV ds, ах
MOV ebx, 0 ; лічильник циклу
LEA edi, str1 ; ефективна адреса рядка
MOV ah, 13 ; старший байт записуваних слів
c1: MOV al [ebx + edi] ; символ з рядка -> AL
MOV es:[ebx*2], ах ; АХ -> сегмент висновку
INC ebx
CMP ebx, 9 ; послеусловие
JB c1
MOV ebx, 0 ; лічильник циклу
LEA edi, str2
MOV ah, 14
c2: MOV al, ss:[ebx + edi] ; символ з рядка -> AL
MOV es:[160 + ebx*2], ах ; АХ -> сегмент висновку
INC ebx
CMP ebx, 9 ; послеусловие
JB c2
MOV ebx, 0 ; лічильник циклу
LEA edi, str3 ; ефективна адреса рядка
MOV AH, 15 ; старший байт записуваних слів
c3: MOV al, cs:[ebx + edi] ; символ з рядка -> AL
MOV es:[320 + ebx*2], ах ; АХ -> сегмент висновку
INC ebx
CMP ebx, 8 ; послеусловие
JB c3
JMP over
str3 DB 'Строка 3'
over: MOV ah, 1 ; запит символу з клавіатури – використовується в
INT 21h ; якості затримки для перевірки висновку на екран
MOV ах, 4c00h ; вихід в Ос
INT 21h
CODE ENDS
END start ; start – точка входу в програму