Команди організації циклів

 

Вхідний контроль:

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 M1.

 

Створення програм на мові Асемблер-86

 

Лінійні програми

 

Вхідний контроль:

1 Які ділянки програм називаються лінійними?

2 Команда з якою адресою буде виконуватись після команди

7000:0100 MOV AX,7000H;?

 

У сучасних додатках рідко використовується програмне забезпечення, цілком написане мовою Асемблера. Частіше мова Асемблера використовується разом з мовою високого рівня, наприклад, С/С++. Частина програми, написана мовою Асемблера, зазвичай призначена для керування периферійними пристроями, оскільки рішення таких задач на мовах високого рівня є більш складним і менш ефективним. Крім того, програми на мові Асемблер виконуються значно швидше, ніж написані будь-якою мовою високого рівня.

Основним принципом отримання ефективних програм є ефективний розподіл та використання ресурсів процесора. Оптимізація програми реалізується за рахунок мінімізації пересилань, використання вказівників на дані замість самих даних при роботі зі складними структурами, розміщення структури даних в одній локальній області пам'яті, розподіл регістрів для локальної ділянки програми тощо. Так, перш за все розподіляються спеціалізовані регістри, а решта виділяється для зберігання найбільш часто використовуваних даних. Дані, які використовуються одноразово, слід зберігати у пам’яті. Акумулятор виділяється для зберігання оперативних результатів.

Потрібна міра оптимальності програми визначається умовами її експлуатації і залежить від багатьох факторів. Для рідко використовуваних програм високий рівень оптимізації не є обов’язковий. Простіше за все оптимізація програми реалізується на лінійних послідовностях команд. У середині лінійних ділянок робиться присвоювання, виконуються операції над даними, вилучаються зайві операції за рахунок одноразового програмування загальних виразів з подальшим включенням їх у циклічні програми. Більш складною задачею є виконання еквівалентних адекватних перетворювань на лінійних ділянках з метою спрощення аналітичних виразів при збереженні достатньої точності та надійності обчислень.

 

Приклад 9.4.1 Ввести з портів з адресами 3F8H та 2F8H дані та запам’ятати їх у суміжних комірках пам’яті, починаючи з адреси 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

 

Припустимо, що перше дане D1 становить 12Н (00010010В), а друге D2 – 34Н (00110100В). Округлення першого даного дасть півбайт, який дорівнює 0001В, а другого – 0011В. Упаковане дане складатиме 00010011В або 13Н.

Програма складена з урахуванням подальшої можливості введення із портів масивів даних, їх упакування та запам’ятовування.

 

Приклад 9.4.2 Число -28Н записати у регістри DL та у прямому коді двома способами. Наступні фрагменти програми виконують ці записи:

 

а) MOV DL,-28H б) MOV DH,-28H

NEG DL NOT DН

OR DL,80H ADD DН,81H

 

Запис будь-якого від’ємного числа здійснюється у регістр у доповнювальному коді, тобто у регістрах DL та DH після виконання перших двох команд буде записане число -28Н у доповнювальному коді, тобто число D8H. Для подання цього даного у прямому коді можна використати команду NEG DL, яка подасть це число без знака, а саме 28Н, та команду OR DL,80H, яка установить 1 у старшому розряді. В результаті отримаємо прямий код числа -28Н, який дорівнює А8Н (фрагмент а)). У фрагменті б) число D8H, записане у регістр у доповнювальному коді, інвертується і до нього додається число 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

 

При виконанні віднімання отримуємо вміст акумулятора:

 

а) _4EH б) _2AH в) _2AH

2AH4EH E4H

24H DCH 46H

 

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Н. Це відповідає такому режиму: немає контролю на парність (D3 = 0, D4 = X), один стоповий біт (D2 = 0), кількість бітів дорівнює 8 (D1 = 1, D2 = 1).

 

Приклад 9.4.6 Два байти D1 та D2 є 3- та 5-м елементами масиву, що починається з ефективної адреси 0010Н. Інвертувати перший байт, вирізати 0, 2, 7 розряди другого; отримані результати зберегти у стеку. Припустимо, що перший байт D1 дорівнює 25Н, а другий D2 – 73Н. Виконаємо вказані операції порозрядно та вкажемо ознаки результату (прапорці) на кожному кроці виконання. Сегменти стека та даних є суміщені.

 

F1= 11011010 = DAH.

F2 = D2 /\ 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 Виконати операцію виключного АБО над двома словами, D1 та D2, що розміщені у пам’яті. Помножити результат на беззнакове число 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

 

Тоді перше слово D1 становить 4371Н, а друге D2 дорівнює 7345Н. Перший проміжний результат F1 становить:

 

F1=DD2=3034Н.

 

 

Ознаки результату становлять OF = 0, CF = 0, SF = 0, AF = 0, ZF = 0, PF = 0.

Другий результат F2 становить:

 

F2 = F1 ´ 33H = 3034H ´ 33H = 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-розрядне число (останнє тільки для МП I80386 та старших).

Зміщення вважається знаковим, тому є можливий перехід у бік початку або кінця програми. Змінюється тільки вказівник команд 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 байт. Для МП I80386 та старших можна використовувати зміщення, що займає 2 або 4 байти. Вміст регістра СS не змінюється.

Якщо ж потрібна адреса знаходиться поза даним сегментом коду, використовують команду умовного переходу з протилежною умовою, а за нею вміщують вже команду безумовного переходу з необхідною адресою.

Достатньо розповсюдженим є випадок, коли розгалуження програм виконується залежно від результату порівняння двох операндів за допомогою команди CMP – порівняння, як знакових, так і беззнакових чисел.

 

Приклад 9.4.8 Два однобайтових беззнакових даних D1 та D2 зберігаються у стеку. Перше дане міститься за молодшою адресою стека, друге – за старшою. Якщо різниця між першим та другим даними є негативна і кількість одиниць в ній непарна, то слід:

– збільшити перше дане на 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, треба по черзі завантажувати дані D1 та D2 так, щоб кожного разу виконувалася одна гілка розгалуженої програми , а комірки пам’яті у сегменті даних зі зміщеннями 10Н та 11Н попередньо обнулити, щоб перевірити правильність виконання програми. Якщо перше дане дорівнює 0АН, а друге – 0FH , то при завантаженні регістра АХ із стека після виконання команди POP AX у регістрі AL буде розміщене перше дане – 0AH, а у регістрі АН – друге дане, 0FH. Різниця першого та другого даних після виконання команди SUB BL, BH становить FBH. Установлюється ознака SF = 1, що вказує на одержання негативного результату. Через це буде виконуватися команда JP, чергова за списком, а умовний перехід за командою JNS не виконується.

Кількість одиниць у різниці непарна, тому установлюється ознака (прапорець) PF = 0, і виконується лінійна ділянка програми, що йде за командою УП JP, включаючи команду БП на кінець програми. Сам умовний перехід не виконується. У результаті виконання цього фрагмента у комірці пам’яті зі зміщенням 10Н буде записане число 00H, а у комірці пам’яті зі зміщенням 11Н – число F0H.

Якщо вхідні дані становили відповідно 0FH та 0AH, то їхня різниця буде позитивною – 05Н, і після її обчислення здійснюється перехід до команди з ефективною адресою 012F PUSH AX, за якою вхідні дані будуть розміщені у стеку за попередніми адресами.

Якщо вхідні дані дорівнюють відповідно 0АН та 0ЕН, то в їх різниці FCH буде парна кількість одиниць, і за ознакою PF = 1 команда JP 0126 реалізує умовний перехід. У результаті виконання послідовної ділянки програми, включаючи команду БП на кінець програми, у комірці пам’яті зі зміщенням 10Н буде завантажене число 0СН, а зі зміщенням 11Н – число 0FH.

У табл. 9.5...9.7 подані протоколи виконання різних гілок розгалуженої програми залежно від різних значень вхідних даних D1 та D2. Для наочності у стовпчику ІР показано адресу поточно виконуваної команди, а не наступної.

Слід зазначити, що приклад має виключно навчальне значення.


Таблиця 9.5 – Протокол виконання програми D1 = 0AH, D2 = 0FH

№ пп. Мнемоніка команд IP AX BX SP DS SS CS PF SF ZF CF
MOV AX,0F0A 0F0A FFEE
PUSH AX 010С 0F0A FFEC
POP AX 010D 0F0A FFEE
MOV BX,AX 010E 0F0A 0F0A FFEE
SUB BL,BH 0F0A 0FFB FFEE
JNS 0128 0F0A 0FFB FFEE
JP 011F 0F0A 0FFB FFEE
ADD AL,05 0F0F 0FFB FFEE
NOT AH F00F 0FFB FFEE
MOV[10],AX 011A F00F 0FFB FFEE
JMP 0129 F00F 0FFB FFEE
NOP F00F 0FFB FFEE

 

Таблиця 9.6 – Протокол виконання програми D1 = 0FH, D2 = 0АН

№ пп. Мнемоніка команд IP AX BX SP DS SS CS PF SF ZF CF
MOV AX,0А0F 0A0F FFEE
PUSH AX 010C 0A0F FFEC
POP AX 010D 0A0F FFEE
MOV BX,AX 010E 0A0F 0A0F FFEE
SUB BL,BH 0A0F 0A05 FFEE
JNS 0129 0A0F 0A05 FFEE
PUSH AX 0A0F 0A05 FFEC
NOP 0A0F 0A05 FFEC

 

Таблиця 9.7 – Протокол виконання програми D1 = 0AH, D2 = 0EH

№ пп. Мнемоніка команд IP AX BX SP DS SS CS PF SF ZF CF
MOV AX,0E0A 0E0A FFEE
PUSH AX 010C 0E0A FFEC
POP AX 010D 0E0A FFEE
MOV BX,AX 010E 0E0A 0E0A FFEE
SUB BL,BH 0E0A 0EFC FFEE
JNS 0128 0E0A 0EFC FFEE
JP 011F 0E0A 0EFC FFEE
ADD AL,02 011F 0E0C 0EFC FFEE
INC AH 0F0C 0EFC FFEE
MOV[0010],AX 0F0C 0EFC FFEE
JMP 0129 0F0C 0EFC FFEE
NOP 0F0C 0EFC FFEE

 

Контрольні питання:

1 З якою метою у програмах реалізуються БП?

2 Чи зберігається адреса повернення до основної програми, якщо реалізується безумовний перехід?

3 Знайти добуток двох однобайтових даних, що зберігаються у регістрі АХ. Якщо одержаний результат від’ємний і вміщує парну кількість одиниць, то до нього треба додати одиницю і запам’ятати у стеку. Якщо кількість одиниць непарна, то добуток треба подати у прямому коді і записати у сегменті даних за зміщенням 0012H. Якщо добуток додатний, його треба запам’ятати у сегменті даних за адресою 7000:0014Н. Значення вхідних даних задати самостійно.

 

Контрольні питання підвищеної складності:

1 Знайти частку від ділення двох однобайтових даних. Ділене знаходиться у регістрі АН, а дільник у регістрі AL. Якщо одержаний результат від’ємний і вміщує парну кількість одиниць, то до нього треба додати одиницю і запам’ятати у стеку. Якщо кількість одиниць непарна, то частку треба подати у прямому коді за зміщенням 0012H. Якщо частка додатна, її треба запам’ятати у сегменті даних за адресою 7000:0016Н. Значення вхідних даних задати самостійно.

2 Перевірити, чи буде вірний фрагмент програми

7000:0120 CMP AL,BL

7000:0122 JZ 8000:0100

 

Циклічні програми

 

Вхідний контроль:

1 Чи завжди у циклічній частині програми треба вказувати необхідну кількість повторень циклу?

2 Наведіть приклади організації циклів за допомогою команд мови Асемблер і покажіть, як вони реалізуються.

 

Програми, в яких багаторазово виконуються ті ж самі ділянки обчислень, як правило, з різними значеннями вхідних даних, називаються циклічними, а послідовність команд, що повторюються, циклами. Цикли з наперед заданою кількістю повторень називаються арифметичними. Цикли, що не мають заздалегідь заданої кількості повторень, називаються ітераційними. Вихід з них відбувається при виконанні заданої умови. Для реалізації арифметичних циклів треба організувати лічильник циклів. За умовчанням для організації лічильника циклів призначений регістр СХ (ЕСХ у МП І80386 та старших). Якщо лічильник спадний, то при виконанні кожного циклу із його вмісту віднімається одиниця. Цикли повторюються доти, доки вміст лічильника буде більший за нуль. Циклічна програма вважається завершеною, якщо лічильник дорівнює нулю. Рідше використовуються зростаючі лічильники. При роботі з масивами закінчувати цикли можна також при досягненні поточної адреси елемента масиву адреси його останнього елемента. Як лічильник циклів можна використовувати будь-який регістр загального призначення, але у системі команд мови Асемблера існують спеціальні команди умовного переходу, в яких перевіряється вміст регістра СХ (ЕСХ).

 

Приклад 9.4.9 Перед записом байта даних у регістр передавача послідовного асинхронного адаптера RS-232-C треба перевірити, чи вільний є регістр зберігання передавача, тобто чи завершено передавання попереднього символу. Ознакою “порожнього” регістра зберігання є установлений в 1 п’ятий біт регістра стану лінії з адресою 3FDH. Наступний фрагмент програми реалізує цю перевірку у циклі:

 

MOV DX,3FDH ; Завантаження адреси регістра стану лінії

M1: IN AL,DX ; Введення байта стану лінії

AND AL,20H ; Регістр зберігання передавача

JZ M1 ; порожній, D5 = 1?

NOP

 

Приклад 9.4.10 Перед прийомом даних з порту приймача послідовного асинхронного адаптера RS-232-C треба перевірити, чи прийняте з лінії дане перебуває у буферному регістрі приймача. Ознакою цього є наявність 1 у нульовому біті регістра стану лінії з адресою 3FDH. Наступний фрагмент програми реалізує цю перевірку в циклі:

 

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 = 10H однобайтових елементів зі знаками розміщений у сегменті даних, починаючи з ефективної адреси 20H; розсортувати елементи масиву на додатні М(P) та від’ємні М(NEG) і запам’ятати додатні елементи в області пам’яті MP, починаючи з ефективної адреси 30H, а від’ємні елементи в області пам’яті MNEG, починаючи з ефективної адреси 40H. Сегменти 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 = 10H, що зберігаються у пам’яті в доповняльному коді, починаючи з адреси 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

 

Сума елементів масиву вміщується в акумуляторі АХ, результат треба запам’ятовувати за ефективною адресою 30H.

 

Приклад 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 мкс.

 

.

 

При Х = 49D отримаємо 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 і розмістити результат за зміщенням 0020H. Початкова адреса двовимірного масиву 7000:0010.

2 Скільки разів буде повторено цикл, якщо у лічильних циклів CL буде спочатку занесено число 2?