Вхідний контроль:
1 Які види циклічних програм Ви знаєте?
2 В чому полягає різниця між арифметичним та ітераційним циклами?
3 В якому регістрі організується програмний лічильник циклів?
4 Наведіть приклади організації циклів будь-якою мовою високого рівня.
5 Покажіть на прикладах, як задається кількість повторень циклів будь-якою мовою високого рівня.
До команд управління циклом відносяться:
– команди організації циклу з лічильником ЕСХ/СХ;
– команди організації циклу з лічильником ЕСХ/СХ з можливістю дострокового виходу з циклу за додатковою умовою.
До першої групи відносяться команди:
JCXZ (Jump if CX=Zero) – перехід, якщо СХ дорівнює 0;
JECXZ (Jump if ECX=Zero) – перехід, якщо ЕСХ дорівнює 0.
Операндом в усіх командах слугує зміщення (мітка), за допомогою якого визначається адреса переходу.
Команди перевіряють вміст відповідного лічильника і якщо його вміст дорівнює 0, відбувається перехід на вказане у команді зміщення (мітку), а якщо не дорівнює, то виконується наступна команда.
До команд другої групи відносяться команди:
LOOP (LOOP control by register CX) – управління циклом за вмістом регістра СХ;
LOOPE/LOOPZ (LOOP control by register CX not equal 0 and ZF=1) – управління циклом за вмістом регістра СХ з урахуванням значення прапорця ZF;
LOOPNE/LOOPNZ (LOOP control by register CX not equal 0 and ZF=0) – управління циклом за вмістом регістра СХ з урахуванням значення прапорця ZF.
Команда LOOP <адреса> забезпечує умовний перехід для циклічного виконання ділянки програми. Кількість повторень циклу визначається вмістом регістра ЕСХ/СХ. Усі різновиди команди LOOP автоматично виконують декремент вмісту ЕСХ/СХ і зупиняють виконання циклу, якщо вміст лічильника дорівнює 0.
Команди LOOPE/LOOPZ є різновидами однієї команди, так само як і команди LOOPNE/LOOPNZ. Алгоритм виконання цих команд однаковий. Команди декрементують вміст ЕСХ/СХ й аналізують його вміст і значення прапорця ZF, якщо вміст ЕСХ/СХ дорівнює 0, то виконується наступна за LOOPхх команда, якщо вміст ЕСХ/СХ дорівнює 1, то виконується перехід до початку циклу. Якщо значення ZF = 0, то команди LOOPE/LOOPZ виконують вихід з циклу, а команди LOOPNE/LOOPNZ повертаються до початку циклу. Для значення ZF = 1 команди виконується навпаки. Команди LOOPNE/LOOPNZ можливо використовувати для пошуку першого нульового елементу у рядку даних, якщо безпосередньо перед цією командою виконати порівнювання елемента з 0, а команди LOOPE/LOOPZ для пошуку першого ненульового елемента.
Контрольні питання:
1 Які групи команд управління циклом Ви знаєте?
2 Що слугує операндом у командах управління циклом?
3 Як виконується декремент вмісту регістра-лічильника CX у програмі при використанні команд JCXZ і LOOP?
4 Які прапорці перевіряє команда LOOPЕ?
Контрольні питання підвищеної складності:
1 Для чого використовується мітка в командах передачі управління?
2 Яка команда буде виконуватися після виконання команди LOOPNZ М 1
M1: MOV AX,DX
…
LOOPNZ М1
NOP,
якщо до її виконання в регістрі СХ було записано число 0001 Н?
3 Як можливо використовувати команди LOOPE/LOOPZ при обробленні рядків даних?
4 Скільки разів буде виконуватись команда LOOPE М 1, якщо до початку циклу в регістр СХ був записаний нуль?
5 Наведіть фрагмент програми, в якому вихід з циклу здійснювався б за умовою JPO M 1.
Створення програм на мові Асемблер-86
Лінійні програми
Вхідний контроль:
1 Які ділянки програм називаються лінійними?
2 Команда з якою адресою буде виконуватись після команди
7000:0100 MOV AX,7000H;?
У сучасних додатках рідко використовується програмне забезпечення, цілком написане мовою Асемблера. Частіше мова Асемблера використовується разом з мовою високого рівня, наприклад, С/С ++. Частина програми, написана мовою Асемблера, зазвичай призначена для керування периферійними пристроями, оскільки рішення таких задач на мовах високого рівня є більш складним і менш ефективним. Крім того, програми на мові Асемблер виконуються значно швидше, ніж написані будь-якою мовою високого рівня.
Основним принципом отримання ефективних програм є ефективний розподіл та використання ресурсів процесора. Оптимізація програми реалізується за рахунок мінімізації пересилань, використання вказівників на дані замість самих даних при роботі зі складними структурами, розміщення структури даних в одній локальній області пам'яті, розподіл регістрів для локальної ділянки програми тощо. Так, перш за все розподіляються спеціалізовані регістри, а решта виділяється для зберігання найбільш часто використовуваних даних. Дані, які використовуються одноразово, слід зберігати у пам’яті. Акумулятор виділяється для зберігання оперативних результатів.
Потрібна міра оптимальності програми визначається умовами її експлуатації і залежить від багатьох факторів. Для рідко використовуваних програм високий рівень оптимізації не є обов’язковий. Простіше за все оптимізація програми реалізується на лінійних послідовностях команд. У середині лінійних ділянок робиться присвоювання, виконуються операції над даними, вилучаються зайві операції за рахунок одноразового програмування загальних виразів з подальшим включенням їх у циклічні програми. Більш складною задачею є виконання еквівалентних адекватних перетворювань на лінійних ділянках з метою спрощення аналітичних виразів при збереженні достатньої точності та надійності обчислень.
Приклад 9.4.1 Ввести з портів з адресами 3 F 8 H та 2 F 8 H дані та запам’ятати їх у суміжних комірках пам’яті, починаючи з адреси 0020Н у сегменті даних. Округлити їх до 4-х розрядів, упакувати в один байт і зберегти у пам’яті за адресою 0030 Н у сегменті даних.
Під упакуванням розуміють розміщення у старшому півбайті першого числа, а в молодшому півбайті – другого числа.
Задача вирішується за виконанням наступного фрагмента програми:
MOV DX,3F8H; Завантаження у регістр DX адреси порту 3F8H
MOV SI,0020H; Завантаження в індексний регістр SI адреси комірки
; пам’яті для першого даного
MOV DI,0030H; Завантаження у індексний регістр DI адреси комірки
; пам’яті для упакованого даного
MOV CL,04H; Завантаження у CL кількості операції зсувів
XOR СН,СН; Обнулення регістра СН
IN AL,DX; Введення в акумулятор першого даного з порту
MOV CH,AL; Запам’ятовування першого даного у регістрі СН
MOV [SI],AL; Запам’ятовування першого даного у пам’яті
MOV DX,2F8H; Завантаження у регістр DX адреси порту 2F8H
IN AL,DX; Введення в акумулятор другого даного з порту
INC SI; Нарощування адреси комірки пам’яті для другого
; даного
MOV [SI],AL; Запам’ятовування другого даного у пам’яті
AND CH,F0H; Округлення першого даного
AND AL,F0H; Округлення другого даного
SHR AL,CL; Переміщення округленого другого даного на місце
; другого півбайта
OR CH,AL; Упаковування даних в один байт
MOV [DI],CH; Запам’ятовування упакованих даних
NOP
Припустимо, що перше дане D 1 становить 12 Н (00010010 В), а друге D 2 – 34 Н (00110100 В). Округлення першого даного дасть півбайт, який дорівнює 0001 В, а другого – 0011 В. Упаковане дане складатиме 00010011 В або 13 Н.
Програма складена з урахуванням подальшої можливості введення із портів масивів даних, їх упакування та запам’ятовування.
Приклад 9.4.2 Число -28 Н записати у регістри DL та DН у прямому коді двома способами. Наступні фрагменти програми виконують ці записи:
а) MOV DL,-28H б) MOV DH,-28H
NEG DL NOT DН
OR DL,80H ADD DН,81H
Запис будь-якого від’ємного числа здійснюється у регістр у доповнювальному коді, тобто у регістрах DL та DH після виконання перших двох команд буде записане число -28 Н у доповнювальному коді, тобто число D 8 H. Для подання цього даного у прямому коді можна використати команду NEG DL, яка подасть це число без знака, а саме 28 Н, та команду OR DL,80 H, яка установить 1 у старшому розряді. В результаті отримаємо прямий код числа -28 Н, який дорівнює А 8 Н (фрагмент а)). У фрагменті б) число D 8 H, записане у регістр DН у доповнювальному коді, інвертується і до нього додається число 81 Н. Ця операція установлює 1 у старшому розряді результату і додає 1 до молодшого розряду; у регістрі DL буде записане також число А 8 Н.
Приклад 9.4.3 Охарактеризувати ознаками ZF, SF та PF дане, яке зберігається у регістрі AL. Команда
OR AL,AL
не змінює дане, яке зберігається в AL, і виставляє зазначені ознаки. У припущенні, що дане є число 56 Н, ознаки дорівнюватимуть:
ZF =0;
SF =0;
PF =1.
Приклад 9.4.4 Знайти вміст акумулятора та ознак CF, SF, AF після виконання фрагментів програм:
а) MOV AL,EH б) MOV AL,2AH в) MOV AL,2AH
SUВ AL,2AH SUB AL,4EH SUB AL,E4H
NOP NOP NOP
При виконанні віднімання отримуємо вміст акумулятора:
а) _4 EH б) _2 AH в) _2 AH
2 AH 4 EH E 4 H
24 H DCH 46 H
CF =0 CF =1 CF =1
AF =0 AF =1 AF =0
SF =0 SF =1 SF =0
Ознака CF установлюється в 1, якщо мала місце позика, тобто у фрагментах б) та в). При відніманні із меншого числа більшого ознака CF завжди установлюється в 1, а ознака знаку SF =1 тільки у разі отримання “коректного” результату, тобто за відсутності переповнення розрядної сітки. Для виявлення меншого з двох чисел слід користуватися ознакою CF, якщо аналізується результат виконання команд віднімання або порівняння.
Приклад 9.4.5 При завантаженні комп’ютера тестуються наявні асинхронні адаптери й ініціалізуються перші два з них: СОМ 1 та СОМ 2, які мають базові адреси 0000:0400 Н та 0000:0300 Н. Наступний фрагмент програми дозволяє прочитати з регістра керування з адресою 3FBH порту СОМ 1 байт стану режиму адаптера:
MOV DX,3FBH; Завантаження адреси керувального регістра у DX
IN AL,DX; Введення поточного режиму адаптера
При правильній ініціалізації байт стану дорівнюватиме 000Х0011 В = 03 Н або 13 Н. Це відповідає такому режиму: немає контролю на парність (D 3 = 0, D 4 = X), один стоповий біт (D 2 = 0), кількість бітів дорівнює 8 (D 1 = 1, D 2 = 1).
Приклад 9.4.6 Два байти D 1 та D 2 є 3- та 5-м елементами масиву, що починається з ефективної адреси 0010Н. Інвертувати перший байт, вирізати 0, 2, 7 розряди другого; отримані результати зберегти у стеку. Припустимо, що перший байт D 1 дорівнює 25 Н, а другий D 2 – 73 Н. Виконаємо вказані операції порозрядно та вкажемо ознаки результату (прапорці) на кожному кроці виконання. Сегменти стека та даних є суміщені.
F 1= 11011010 = DAH.
F 2 = D 2 /\ mask; mask = 01111010 = 7 АH.
Задамо довільно 16 елементів масиву байтів, з яких третій дорівнює 25 Н, а п’ятий дорівнює 73 Н.
7000:0010 12 34 56 25 43 73 43 54 65 76 82 37 15 13 14 61 52.
Вказівник стека задамо таким, який дорівнює 2080 Н.
Структурна схема програми наведена на рис. 9.12.
Фрагмент програми, яка вирішує цю задачу, має вид
MOV AX,7000H; Завантаження
MOV DS,AX; сегментних
MOV SS,AX; регістрів
MOV SP,2080H; Завантаження вказівника стека
MOV BX,0010H; Завантаження базового регістра
MOV AL,[BX+03]; Пересилання першого байта до AL
NOT AL; Інвертування першого байта
MOV AH,[BX+05]; Пересилання другого байта до АН
AND AH,7AH; Змінення другого байта
PUSH AX; Запам’ятовування результатів у стеку
Рисунок 9.12 – Структурна схема програми
Програма виконується так.
Усі команди пересилань та команда NOT не змінюють прапорці; результатом виконання команди NOT є число DAH, що вміщується у регістрі AL, а результатом команди AND є число 72 Н, що вміщується в АН; ця команда установлює прапорці OF = 0, CF = 0, SF = 0, AF = 0, ZF = 0, PF = 1.
Приклад 9.4.7 Виконати операцію виключного АБО над двома словами, D 1 та D 2, що розміщені у пам’яті. Помножити результат на беззнакове число 33Н і розташувати добуток на місці другого слова. Перше знаходиться у масиві, що починається зі зміщення 10 Н та адресоване вмістом індексного регістра SI, а друге знаходиться у масиві, що починається зі зміщення 20 Н та адресується вмістом індексного регістра DI і зміщенням 2 Н. Початкова адреса сегмента даних є 7000 Н.
Створимо два масиви, починаючи зі зміщення 10 Н та 20 Н відповідно. Припустимо, що у регістрі SI міститься число 6 Н, а у регістрі DI – число 2 Н.
7000:0010 12 34 56 25 40 43 71 43 65 76 82 37 15 13 18 60
7000:0020 14 36 58 27 45 73 48 54 65 76 82 39 17 15 14 61
Тоді перше слово D 1 становить 4371 Н, а друге D 2 дорівнює 7345 Н. Перший проміжний результат F 1 становить:
F 1= D 1Å D 2=3034 Н.
Ознаки результату становлять OF = 0, CF = 0, SF = 0, AF = 0, ZF = 0, PF = 0.
Другий результат F 2 становить:
F 2 = F 1 ´ 33 H = 3034 H ´ 33 H = 99 А 5 СН.
Ознаки результату дорівнюють: OF = 1, CF = 1, SF = 1, AF = 1, ZF = 0.
Програма має вигляд:
MOV AX,7000H; Організація
MOV DS,AX; сегмента даних
MOV BX,0010H; Завантаження до ВХ початкової адреси першого
; масиву
MOV DI,2H; Завантаження
MOV SI,6H; індексних регістрів
XOR DX,DX; Обнулення DX
MOV AX,[BX+SI]; Завантаження першого слова до АХ
MOV BX,0020H; Завантаження до ВХ початкової адреси другого
; масиву
XOR AX,[BX+DI+2]; Складання за модулем 2 з другим словом
MOV CХ,33H; Завантаження множника до CL
MUL CХ; Множення на константу 33Н
MOV [BX+DI+2],AX; Пересилання молодшого слова добутку на місце
; другого слова
MOV [BX+DI+4],DX; Пересилання старшого слова добутку до другого
; масиву
Після виконання програми в регістр АХ буде записане число 9 А 5 СН, а в регістр DX – число 0009 Н.
Контрольні питання:
1 Як подаються числа беззнакові та зі знаком у МП сім’ї Intel?
2 Подані в яких системах числення дані можуть оброблюватись у МП сім’ї Intel?
3 Четвертий елемент першого масиву дорівнює 32 Н. Поділити його на п’ятий елемент другого масиву, що дорівнює 4 Н, усіма відомими вам способами.
4 Інвертувати слово, що становить п’ятий елемент першого масиву; поділити результат на третій елемент другого масиву. Частку разом з регістром прапорців запам’ятати у стеку.
5 Знайти логічний добуток четвертого байта першого масиву та третього байта другого масиву. Результат помножити на 44 Н, добуток запам’ятати за ефективною адресою, що визначається вмістом регістра DI.
6 Заповнити масив з чотирьох слів, починаючи з адреси DS: 50, використовуючи команду STOSW.
7 Порівняти нульовий елемент першого масиву з другим елементом другого масиву. Запам’ятати у стеку вміст регістра прапорців та суму вказаних елементів.
Контрольні питання підвищеної складності:
1 Завантажити одночасно регістр сегмента даних та акумулятор двобайтовими елементами першого масиву, починаючи з другого елемента за допомогою прямого адресування.
2 Сумістити сегмент даних та додатковий сегмент даних.
Розгалужені програми
Вхідний контроль:
1 За якими умовами (прапорцями) можна реалізувати умовні переходи?
2 Напишіть команду безумовного переходу на адресу команди, яка знаходиться в іншому сегменті кодів.
У послідовних ділянках програми виконання команд відбувається згідно з їхнім розташуванням. Однак за умовами тієї чи іншої задачі може виникнути необхідність зміни порядку виконання команд. Це реалізується за допомогою команд, призначених для передачі керування з однієї точки програми до іншої. При виконанні будь-якої команди відбувається нарощування вмісту вказівника команд IP, що дозволяє одержати адресу наступної виконуваної команди у лінійних програмах. Якщо ж треба перейти до потрібної адреси у програмі, використовують безпосередню зміну значення вказівника команди IP та/або значення сегментного регістра коду CS за допомогою команд умовного та безумовного переходів. Розрізняють команди дальнього (far), близького (near) та короткого (short) переходів. При дальньому переході змінюється не тільки вміст вказівника команд IP, але й вміст сегментного регістра коду CS, тобто можливий перехід до будь-якої комірки пам’яті, на відстань, більшу ніж 216 адрес комірок пам’яті, а не тільки у межах сегмента коду. Це дає можливість реалізувати міжсегментні переходи до будь-якого сегмента, наприклад, при виконанні підпрограм. Цей сегмент потім стає поточним сегментом коду. При близькому переході змінюється тільки вміст вказівника команд IP у межах [-216... +216-1] адрес, а вміст сегментного регістра CS не змінюється, тобто перехід можливий тільки у сегменті коду CS. При короткому переході межі змінення вказівника команд IP становлять [-128...+127] адрес.
Безумовний перехід
Команди безумовного переходу (БП) дозволяють перейти на задану адресу програми без запам’ятовування адреси повернення. Є можливими три форми мнемонічного подання команди безумовного переходу:
JMP 0110H; Прямий перехід на адресу 0110Н
JMP [offset]; Перехід за зміщенням відносно поточного вмісту
; вказівника команд IP
JMP [operand]; Непрямий перехід; адреса переходу вміщується до
; регістрів загального призначення або до комірок
; пам’яті
При прямому переході адреса переходу замінює вміст вказівника команд і, за необхідності, вміст сегментного регістра коду.
Зміщення являє собою 8-, 16- та 32-розрядне число (останнє тільки для МП I 80386 та старших).
Зміщення вважається знаковим, тому є можливий перехід у бік початку або кінця програми. Змінюється тільки вказівник команд IP, а сегментний регістр CS залишається незмінним.
При непрямому переході адреса продовження програми визначається вмістом одного із 16- (АХ, ВХ, СХ, DX, SI, DI, BP, SP) або 32- (EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP – для старших моделей) розрядних регістрів загального призначення або ділянки пам’яті. У першому випадку реалізується короткий або близький перехід, а у другому і третьому випадках перехід може бути також і далеким. Вміст вказаного у команді регістра або ділянки пам’яті є новим вмістом вказівника команд IP та за необхідності сегментного регістра коду CS. У наступних фрагментах програми показані можливі варіанти указання адреси при безумовних переходах.
CS: IP
7000: 30 MOV DS,AX; Завантаження DS з АХ
7000: 32 MOV AX,1234H; Завантаження АХ даним 1234Н
7000: 35 JMP 0039H; Обхід команди MOV CX,AX
7000: 37 MOV CX,AX; Завантаження СХ з АХ
7000: 39 MOV DX,AX; Завантаження DX з АХ
CS: IP
7000: 30 MOV DS,AX; Фрагмент
7000: 32 MOV AX,0039H; програми
7000: 35 JMP AX; аналогічний
7000: 37 MOV CX,AX; попередньому
7000: 39 MOV DX,AX
CS: IP
7000: 30 MOV AX,003CH; Фрагмент
7000: 33 MOV [ 50],AX; програми
7000: 36 JMP [50]; аналогічний
7000: 3A MOV CX,AX; попередньому
7000: 3C MOV DX,AX
Прапорці при виконанні команд безумовних переходів не змінюються.
Умовні переходи
Умовні переходи (УП) у програмах здійснюються при виконанні вказаних у них умов залежно від одержаного перед УП результату і не реалізуються, якщо зазначені умови не виконані, тоді виконується ділянка програми, що йде безпосередньо за командою умовного переходу. Команди умовних переходів наводяться у табл. 9.4. Для деяких умов існують кілька команд умовного переходу. Використання певної команди залежить тільки від програміста. Умови “вище” або “нижче” відносяться до величин без знака, а “більше” та “менше” до величин зі знаком. Зміщення у командах умовного переходу – це величини у діапазоні -128...+127, тобто вони займають 1 байт. Для МП I 80386 та старших можна використовувати зміщення, що займає 2 або 4 байти. Вміст регістра СS не змінюється.
Якщо ж потрібна адреса знаходиться поза даним сегментом коду, використовують команду умовного переходу з протилежною умовою, а за нею вміщують вже команду безумовного переходу з необхідною адресою.
Достатньо розповсюдженим є випадок, коли розгалуження програм виконується залежно від результату порівняння двох операндів за допомогою команди CMP – порівняння, як знакових, так і беззнакових чисел.
Приклад 9.4.8 Два однобайтових беззнакових даних D 1 та D 2 зберігаються у стеку. Перше дане міститься за молодшою адресою стека, друге – за старшою. Якщо різниця між першим та другим даними є негативна і кількість одиниць в ній непарна, то слід:
– збільшити перше дане на 5 Н;
– інвертувати друге дане;
– отримані результати запам’ятати відповідно за суміжними адресами у сегменті даних зі зміщеннями 10 Н та 11 Н.
У разі парної кількості одиниць у різниці даних необхідно:
– збільшити перше дане на 02 Н;
– збільшити друге слово на 01 Н;
– отримані результати записати за тими самими адресами.
Якщо різниця даних позитивна, їх слід зберегти у стеку.
Структурна схема алгоритму має вид (рис. 9.13).
Рисунок 9.13 – Структурна схема алгоритму
Фрагмент програми розв’язання задачі:
MOV AX,0F0AH; Завантаження даних до АХ
PUSH AX; Завантаження даних до стека
POP AX; Завантаження даних із стека до АХ
MOV BX,AX; Збереження вмісту АХ в ВХ
SUB BL,BH; Різниця даних
JNS POSIT; позитивна?
JP EVEN; Ні, кількість одиниць парна?
ADD AL,05H; Ні, зміна першого слова
NOT AH; Зміна другого даного
MOV [10H],AX; Запам’ятовування нових даних у
; сегменті даних
JMP KІNEC; БП на кінець програми
EVEN: ADD AL,02H; Так, зміна першого даного
INC AH; Інкрементування другого даного
MOV [10],AX; Запам’ятовування даних у сегменті даних
JMP KІNEC; БП на кінець програми
POSIT: PUSH AX; Запам’ятовування вхідних даних у стеку
KІNEC: NOP; Кінець програми
Перед виконанням програми до стека, враховуючи значення вказівника стека SP, треба по черзі завантажувати дані D 1 та D 2 так, щоб кожного разу виконувалася одна гілка розгалуженої програми, а комірки пам’яті у сегменті даних зі зміщеннями 10 Н та 11 Н попередньо обнулити, щоб перевірити правильність виконання програми. Якщо перше дане дорівнює 0 АН, а друге – 0 FH, то при завантаженні регістра АХ із стека після виконання команди POP AX у регістрі AL буде розміщене перше дане – 0 AH, а у регістрі АН – друге дане, 0 FH. Різниця першого та другого даних після виконання команди SUB BL, BH становить FBH. Установлюється ознака SF = 1, що вказує на одержання негативного результату. Через це буде виконуватися команда JP, чергова за списком, а умовний перехід за командою JNS не виконується.
Кількість одиниць у різниці непарна, тому установлюється ознака (прапорець) PF = 0, і виконується лінійна ділянка програми, що йде за командою УП JP, включаючи команду БП на кінець програми. Сам умовний перехід не виконується. У результаті виконання цього фрагмента у комірці пам’яті зі зміщенням 10 Н буде записане число 00 H, а у комірці пам’яті зі зміщенням 11 Н – число F0 H.
Якщо вхідні дані становили відповідно 0 FH та 0 AH, то їхня різниця буде позитивною – 05 Н, і після її обчислення здійснюється перехід до команди з ефективною адресою 012 F PUSH AX, за якою вхідні дані будуть розміщені у стеку за попередніми адресами.
Якщо вхідні дані дорівнюють відповідно 0 АН та 0 ЕН, то в їх різниці FCH буде парна кількість одиниць, і за ознакою PF = 1 команда JP 0126 реалізує умовний перехід. У результаті виконання послідовної ділянки програми, включаючи команду БП на кінець програми, у комірці пам’яті зі зміщенням 10Н буде завантажене число 0 СН, а зі зміщенням 11 Н – число 0 FH.
У табл. 9.5...9.7 подані протоколи виконання різних гілок розгалуженої програми залежно від різних значень вхідних даних D 1 та D 2. Для наочності у стовпчику ІР показано адресу поточно виконуваної команди, а не наступної.
Слід зазначити, що приклад має виключно навчальне значення.
Таблиця 9.5 – Протокол виконання програми D 1 = 0 AH, D 2 = 0 FH
№ пп. | Мнемоніка команд | IP | AX | BX | SP | DS | SS | CS | PF | SF | ZF | CF |
MOV AX,0 F 0 A | 0 F 0 A | FFEE | ||||||||||
PUSH AX | 010 С | 0 F 0 A | FFEC | |||||||||
POP AX | 010 D | 0 F 0 A | FFEE | |||||||||
MOV BX,AX | 010 E | 0 F 0 A | 0 F 0 A | FFEE | ||||||||
SUB BL,BH | 0 F 0 A | 0 FFB | FFEE | |||||||||
JNS 0128 | 0 F 0 A | 0 FFB | FFEE | |||||||||
JP 011 F | 0 F 0 A | 0 FFB | FFEE | |||||||||
ADD AL,05 | 0 F 0 F | 0 FFB | FFEE | |||||||||
NOT AH | F 00 F | 0 FFB | FFEE | |||||||||
MOV [10], AX | 011 A | F 00 F | 0 FFB | FFEE | ||||||||
JMP 0129 | F 00 F | 0 FFB | FFEE | |||||||||
NOP | F 00 F | 0 FFB | FFEE |
Таблиця 9.6 – Протокол виконання програми D1 = 0FH, D2 = 0АН
№ пп. | Мнемоніка команд | IP | AX | BX | SP | DS | SS | CS | PF | SF | ZF | CF |
MOV AX,0 А 0 F | 0 A 0 F | FFEE | ||||||||||
PUSH AX | 010 C | 0 A 0 F | FFEC | |||||||||
POP AX | 010 D | 0 A 0 F | FFEE | |||||||||
MOV BX,AX | 010 E | 0 A 0 F | 0 A 0 F | FFEE | ||||||||
SUB BL,BH | 0 A 0 F | 0 A 05 | FFEE | |||||||||
JNS 0129 | 0 A 0 F | 0 A 05 | FFEE | |||||||||
PUSH AX | 0 A 0 F | 0 A 05 | FFEC | |||||||||
NOP | 0 A 0 F | 0 A 05 | FFEC |
Таблиця 9.7 – Протокол виконання програми D 1 = 0 AH, D 2 = 0 EH
№ пп. | Мнемоніка команд | IP | AX | BX | SP | DS | SS | CS | PF | SF | ZF | CF |
MOV AX,0 E 0 A | 0 E 0 A | FFEE | ||||||||||
PUSH AX | 010 C | 0E0 A | FFEC | |||||||||
POP AX | 010 D | 0 E 0 A | FFEE | |||||||||
MOV BX,AX | 010 E | 0 E 0 A | 0 E 0 A | FFEE | ||||||||
SUB BL,BH | 0 E 0 A | 0 EFC | FFEE | |||||||||
JNS 0128 | 0 E 0 A | 0 EFC | FFEE | |||||||||
JP 011 F | 0 E 0 A | 0 EFC | FFEE | |||||||||
ADD AL,02 | 011 F | 0 E 0 C | 0 EFC | FFEE | ||||||||
INC AH | 0F0 C | 0 EFC | FFEE | |||||||||
MOV [0010], AX | 0F0 C | 0 EFC | FFEE | |||||||||
JMP 0129 | 0 F 0 C | 0 EFC | FFEE | |||||||||
NOP | 0 F 0 C | 0 EFC | FFEE |
Контрольні питання:
1 З якою метою у програмах реалізуються БП?
2 Чи зберігається адреса повернення до основної програми, якщо реалізується безумовний перехід?
3 Знайти добуток двох однобайтових даних, що зберігаються у регістрі АХ. Якщо одержаний результат від’ємний і вміщує парну кількість одиниць, то до нього треба додати одиницю і запам’ятати у стеку. Якщо кількість одиниць непарна, то добуток треба подати у прямому коді і записати у сегменті даних за зміщенням 0012 H. Якщо добуток додатний, його треба запам’ятати у сегменті даних за адресою 7000:0014 Н. Значення вхідних даних задати самостійно.
Контрольні питання підвищеної складності:
1 Знайти частку від ділення двох однобайтових даних. Ділене знаходиться у регістрі АН, а дільник у регістрі AL. Якщо одержаний результат від’ємний і вміщує парну кількість одиниць, то до нього треба додати одиницю і запам’ятати у стеку. Якщо кількість одиниць непарна, то частку треба подати у прямому коді за зміщенням 0012 H. Якщо частка додатна, її треба запам’ятати у сегменті даних за адресою 7000:0016 Н. Значення вхідних даних задати самостійно.
2 Перевірити, чи буде вірний фрагмент програми
7000:0120 CMP AL,BL
7000:0122 JZ 8000:0100
Циклічні програми
Вхідний контроль:
1 Чи завжди у циклічній частині програми треба вказувати необхідну кількість повторень циклу?
2 Наведіть приклади організації циклів за допомогою команд мови Асемблер і покажіть, як вони реалізуються.
Програми, в яких багаторазово виконуються ті ж самі ділянки обчислень, як правило, з різними значеннями вхідних даних, називаються циклічними, а послідовність команд, що повторюються, циклами. Цикли з наперед заданою кількістю повторень називаються арифметичними. Цикли, що не мають заздалегідь заданої кількості повторень, називаються ітераційними. Вихід з них відбувається при виконанні заданої умови. Для реалізації арифметичних циклів треба організувати лічильник циклів. За умовчанням для організації лічильника циклів призначений регістр СХ (ЕСХ у МП І 80386 та старших). Якщо лічильник спадний, то при виконанні кожного циклу із його вмісту віднімається одиниця. Цикли повторюються доти, доки вміст лічильника буде більший за нуль. Циклічна програма вважається завершеною, якщо лічильник дорівнює нулю. Рідше використовуються зростаючі лічильники. При роботі з масивами закінчувати цикли можна також при досягненні поточної адреси елемента масиву адреси його останнього елемента. Як лічильник циклів можна використовувати будь-який регістр загального призначення, але у системі команд мови Асемблера існують спеціальні команди умовного переходу, в яких перевіряється вміст регістра СХ (ЕСХ).
Приклад 9.4.9 Перед записом байта даних у регістр передавача послідовного асинхронного адаптера RS -232- C треба перевірити, чи вільний є регістр зберігання передавача, тобто чи завершено передавання попереднього символу. Ознакою “порожнього” регістра зберігання є установлений в 1 п’ятий біт регістра стану лінії з адресою 3 FDH. Наступний фрагмент програми реалізує цю перевірку у циклі:
MOV DX,3FDH; Завантаження адреси регістра стану лінії
M1: IN AL,DX; Введення байта стану лінії
AND AL,20H; Регістр зберігання передавача
JZ M1; порожній, D5 = 1?
NOP
Приклад 9.4.10 Перед прийомом даних з порту приймача послідовного асинхронного адаптера RS -232- C треба перевірити, чи прийняте з лінії дане перебуває у буферному регістрі приймача. Ознакою цього є наявність 1 у нульовому біті регістра стану лінії з адресою 3 FDH. Наступний фрагмент програми реалізує цю перевірку в циклі:
MOV DX,3FDH; Завантаження адреси порту стану лінії
M1: IN AL,DX; Введення байта стану лінії
AND AL,01H; Перевірка наявності даного у буферному регістрі
; приймача
JZ M1; D0 = 1
Приклад 9.4.11 Знайти у чотириелементному рядку байт, що дорівнює 43 Н, якщо рядок розміщений, починаючи з ефективної адреси 0200Н, а вміст сегментного регістра даних ES дорівнює 7000 Н:
7000:0200 41 42 43 44.
Лічильник байтів у рядку організуємо у регістрі СL, ефективна адреса байтів вміщується в індексний регістр DI, а еталон шуканого байта завантажуємо до AL. Для перепускання неспівпадаючих елементів використовується префікс REPNZ.
MOV AX,7000H;
MOV ES,AX;
MOV CL,0004H; Організація лічильника циклів
MOV DI,0200H; Організація непрямого регістрового адресування
; елементів рядка
MOV AX,0043H; Завантаження еталонного байта до AL
STD; Установлення прапорця напряму
CLD; Скидання прапорця напряму
REPNZ; Організація перепускання неспівпадаючих елементів
SCASB; Сканування байтів рядка
Програма виконується циклічно чотири рази, кожний цикл являє собою лінійну програму. Після сканування усіх байтів рядка в регістрі СХ буде записане число 0001 Н, а в регістрі DI – число 0203 Н, на одиницю більше, ніж адреса шуканого байта. Прапорець ZF установлюється після виконання програми.
Приклад 9.4.12 Одновимірний масив М(N), N = 10 H однобайтових елементів зі знаками розміщений у сегменті даних, починаючи з ефективної адреси 20 H; розсортувати елементи масиву на додатні М(P) та від’ємні М(NEG) і запам’ятати додатні елементи в області пам’яті MP, починаючи з ефективної адреси 30 H, а від’ємні елементи в області пам’яті MNEG, починаючи з ефективної адреси 40 H. Сегменти DS та ES суміщені.
Структурна схема алгоритму наведена на рис. 9.14.
Фрагмент програми розв’язання задачі.
MOV CX,0010H; Завантаження лічильника циклів
MOV SI,0020H; Завантаження адреси первісного масиву
MOV DI,0030H; Завантаження початкової адреси масиву
; додатних елементів
MOV BX,0040H; Завантаження початкової адреси масиву
; від’ємних елементів
СLD; Виставлення автоінкрементування SI та DI
CYCLE: LODSB; Виклик чергового елемента масиву
OR AL,AL; Виставлення ознак елемента масиву
JS NEG; Елемент є додатний?
Р: STOSB; так, запис до масиву додатних чисел
JMP COUNT; БП на команду перевірки лічильника
; циклів
NEG: MOV [BX],AL; ні, запис до масиву чисел
INC BX; Нарощування адреси масиву від’ємних
; чисел
COUNT: LOOP CYCLE; Перевірка лічильника циклів
NOP
Рисунок 9.14 – Структурна схема алгоритму
Приклад 9.4.13 Знайти середнє арифметичне N двобайтових елементів масиву M(N), N = 10 H, що зберігаються у пам’яті в доповняльному коді, починаючи з адреси 7000:0020. Результат розмістити за ефективною адресою 30 Н. Структурна схема алгоритму подана на рис. 9.15.
Рисунок 9.15 – Структурна схема алгоритму
Програма розв’язання задачі.
MOV AX,7000H; Організація сегмента даних,
MOV DS,AX; починаючи з ефективної адреси 7000:0000
MOV BX,0020Н; Завантаження адреси початку масиву
MOV AX,0000H; Обнулення акумулятора (S = 0)
M1: ADD AX,[BX]; Додавання чергового елемента масиву
ADD BX,2; Нарощування адреси чергового елемента
; масиву
CMP BX,0030H; Чи дорівнює адреса чергового елемента масиву
JNZ M1; адресі останього+2? Якщо ні, повернення на
; початок циклу
MOV BX,0010H; Завантаження дільника до BX
IDIV BX; Визначення середнього арифметичного
MOV [30H],AX; Запам’ятовування середнього арифметичного
NOP
Сума елементів масиву вміщується в акумуляторі АХ, результат треба запам’ятовувати за ефективною адресою 30 H.
Приклад 9.4.14 Написати підпрограму часової затримки тривалістю 100 мкс за умови, що тривалість такту 0,1 мкс. Для організації підпрограми затримки, яка найчастіше має назву DELAY, треба використати лічильник для зберігання числа повторень циклів, від якого залежить час затримки. Значення Х обчислюється за формулою
,
де дужки ] [ означають, що дрібна частина відкидається; t з – задане значення затримки; t о – час, потрібний для одноразово виконуваних команд; t ц – час, потрібний для виконання циклічно повторюваних команд. Вибір застосовуваних у підпрограмі команд та обчислення Х являє собою ітераційний процес, тривалість якого залежить від необхідної точності затримки. За наявності високих вимог до точності забезпечуваної затримки можливі два шляхи розв’язання цієї задачі:
1) зменшують отримане значення Х на кілька одиниць, а отримане зменшення компенсують командою NOP, яка виконується багаторазово;
2) змінюють значення t ц за рахунок включення у цикл інших команд.
Наступний фрагмент підпрограми DELAY дає уявлення про принцип програмної реалізації часової затримки:
CALL DELAY; 19 тактів за умови внутрішньосегментного
; переходу
DELAY: MOV AL,X; 2 такти, Х обчислюється за формулою та
; задається у команді з безпосереднім
; адресуванням
TIME: DEC AL; 3 такти
JNZ TIME; 8 тактів
NOP; 2 такти
RET; 8 тактів
На початку підпрограми DELAY, як і в кожній підпрограмі, треба запам’ятати вміст використовуваних регістрів та регістра прапорців:
CALL DELAY; 19 тактів
DELAY: PUSH BX; 11тактів
PUSHF; 10 тактів
MOV BL,X; 2 такти, Х повинен завантажуватись у BL
; як операнд з безпосереднім адресуванням
M1: DEC BL; 3 такти
JNZ M1; 16 тактів
POP F; 8 тактів
POP BX; 8 тактів
RET; 8 тактів
t о = (19+11+10+2+8+8+8)·0,1 = 7,3 мкс;
t ц = (3+16)·0,1 = 1,9 мкс;
t з = 100 мкс.
.
При Х = 49 D отримаємо t з = 6,6 + 49 * 1,9 = 6,6 + 93,1 = 99,7 мкс.
Така точність формування затримки не є достатня і тому до одноразово виконуваних команд треба додати команду, яка б займала 3 такти і виконувалась 0,3 мкс. Це може бути команда OR BL, BL. Остаточно фрагмент підпрограми затримки має вигляд:
DELAY: PUSH BX
PUSHF
MOV BL,31Н
M1: DEC BL
JNZ M1
OR BL,BL
POP F
POP BX
RET
Слід зазначити, що доцільно перед зверненням до підпрограми DELAY заборонити масковані переривання від зовнішніх пристроїв і наступною після команди CALL DELAY вжити команду дозволу переривань.
Контрольні питання:
1 Які програми називаються циклічними?
2 Які види циклічних програм ви знаєте?
3 Які команди умовних переходів використовуються для пошуку в рядку першого нульового або ненульового елемента?
4 Який спосіб адресування використовується при роботі з двовимірними масивами?
5 У масиві N однобайтових чисел, розміщених у пам’яті, починаючи з адреси 7000: 0010 Н, підрахувати суму парних чисел. Результат розмістити за зміщенням 0027 Н.
6 У масиві M(N) однобайтових чисел, розміщених у пам’яті, починаючи з адреси 7000: 0010 Н, підрахувати суму непарних чисел. Результат розмістити за зміщенням 0022 Н.
7 У масиві M(N) однобайтових чисел, розміщених у пам’яті, починаючи з адреси 7000:0010 Н, підрахувати кількість непарних чисел. Результат розмістити за зміщенням 0030 Н.
8 У масиві М(N) двобайтових чисел, розміщених у пам’яті, починаючи з адреси 7000:0010 Н, підрахувати кількість парних чисел. Результат розмістити за зміщенням 0026 Н.
Контрольні питання підвищеної складності:
1 Знайти суму елементів головної діагоналі квадратної матриці N´N і розмістити результат за зміщенням 0020 H. Початкова адреса двовимірного масиву 7000:0010.
2 Скільки разів буде повторено цикл, якщо у лічильних циклів CL буде спочатку занесено число 2?