Інформаційний портал msevm

Цикли, що дозволяють виконати деяку ділянку програми багаторазово, в будь-якій мові є однією з найбільш уживаних конструкцій. В системі команд МП 86 цикли реалізуються, головним чином, за допомогою команди loop (петля), хоча є й інші способи організації циклів. У всіх випадках число кроків в циклі визначається вмістом регістра СХ, тому максимальне число кроків складає 64 К.
Розглянемо простий приклад організації циклу. Нехай в програмі зарезервовано місце для масиву розміром 10000 слів, і цей масив треба заповнити натуральним рядом чисел від 0 до 9999. Ці числа, що заповнюють послідовні елементи масиву, іноді називають числами-заповнювачами. Відповідний фрагмент програми буде виглядати наступним чином:

; У сегменті даних

array dw 10000 dup (0)

; В програмному сегменті

mov AX, 0; Початкове значення заповнювача

mov CX, 10000; Лічильник циклу

fill: mov [BX] [SI], AX; Заповнювач пошлемо в масив

inc AX; Інкремент заповнювач

add SI, 2; модифікація індексу

loop fill; команда циклу

; Організація довгого циклу

mov CX, 10000; Лічильник циклу

fill:; Мітка початку циклу

; Тіло довгого циклу

dec CX; Декремент лічильника циклу

cmp CX, 0; Відпрацьовано задане число кроків?

je finish; Так, на мітку продовження програми

jmp fill; Ні, на початок циклу

finish:; продовження програми

У цьому, вельми типовому фрагменті ми "вручну" зменшуємо вміст лічильника циклу і порівнюємо отримане значення з 0. Якщо СХ = О, це означає, що в циклі виконано задане число кроків, і командою умовного переходу je здійснюється перехід на продовження програми (мітка finish ). Якщо СХ ще не дорівнює нулю, командою безумовного переходу jmp здійснюється повернення в початок циклу. Як було показано в гл. 2, команда jmp дозволяє перейти в будь-яку точку сегмента, і обмеження на розмір тіла циклу знімається.
При необхідності організувати вкладені цикли, для збереження лічильника зовнішнього циклу на час виконання внутрішнього зручно скористатися стеком. У наступному фрагменті організовується тимчасова затримка тривалістю декілька секунд (конкретна величина затримки залежить від швидкості роботи процесора).

outer: push CX; Збережемо його в стеці

mov CX, 0; Лічильник внутрішнього циклу

inner: loop inner; loop внутрішнього циклу

pop CX; Відновимо зовнішній лічильник

loop outher; loop зовнішнього циклу

cmp AX, BX; Порівняння двох регістрів

je equal; Перехід, якщо AX = BX

cmp SI, mem; Порівняння регістра і осередки пам'яті

jne notequ; Перехід, якщо SI<>mem

int 21h; Виклик DOS

jc syserr; Перехід, якщо була помилка

or BX, BX; Аналіз BX

jz zero; Перехід, якщо BX = 0

inpt: in AL, DX; Введення даного з пристрою

test AL, 80h; Аналіз біта 7 в даному

je inpt; Введення до тих пір. Бувай

; Біт 7 = 0 (очікування установки біта 7)

test AX, 7; Аналіз бітів 0,1,2 в AX

jne found; Перехід, якщо хоча б 1 біт

; З них встановлено

test DI, OFh; Аналіз бітів 0. 3 в DI

jz reset; Перехід, якщо всі вони скинуті

mov AX, data; Ініціалізація

move DS, AX; Регістр DS

; Виведемо службове повідомлення

mov AH, 09h; Функція виведення

; Поставимо запит до DOS на введення рядка

mov AH, 3Fh; Функція введення

mov BX, 0; Дескриптор клавіатури

mov CX, 80; Введення максимум 80 байт

mov actlen, AX; Фактично введено

; Перетворимо рядкові українські літери на прописні

mov CX, actlen; Довжина введеного рядка

mov SI, 0; Покажчик в буфері

filter: mov AL, buf [SI]; Візьмемо символ

cmp AL, 'a'; Менше 'a'?

jb noletter; Так, не перетворювати

cmp AL, 'я'; Більше 'я'?

ja noletter; Так, не перетворювати

cmp AL, 'п'; Більше 'п'?

ja more; Так, на подальшу перевірку

sub AL, 20h; 'a' .. 'п'. Перетворимо в прописну

jmp store; На збереження в буфері

more: cmp AL, 'p'; Менше 'p1' (псевдографіка)?

jb noletter;> 'п',<'p'. Не изменять

sub AL, 50h; 'p'. 'Я'. Перетворимо в прописну

store: mov buf [SI], AL; Відправимо назад в buf

noletter: inc SI; пройти показник

loop filter; Цикл по всім символам

; Виведемо результат перетворення на екран для контролю

mov AX, 40h; Функція виведення

mov BX, 1; Дескриптор екрану

mov CX, actlen; Довжина повідомлення

mov AH, 01; Зупинимо програму

int 21h; в очікуванні натиснення клавіші

msg db "Введіть! $"

buf db 80 dup ( ''); Буфер введення

stk segment stack

mul - команда множення чисел без знака;


imul - команда множення чисел зі знаком;


div - команда ділення чисел без знака;


idiv - команда ділення чисел зі знаком.

Пояснимо відмінності цих команд на формальних прикладах.

; Множення позитивних чисел із знаком

mov AL, 5; Перший співмножник дорівнює 5

mov BL, 7; Другий співмножник дорівнює 7

mul BL; AX = 0023h = 35

mov AL, 5; Перший співмножник дорівнює 5

mov BL, 7; Другий співмножник дорівнює 7

imul BL; AX = 0023h = 35

Обидві команди, mul і imul, дають в даному випадку однаковий результат, так як позитивні числа зі знаком збігаються з числами без знака. Не так стоїть справа при множенні негативних чисел.

; Множення негативних чисел зі знаком

mov AL, OFCh; Перший співмножник = 252

mov BL, 4; Другий співмножник = 4

mul BL; AX = 03F0h = 1008

mov AL, OFCh; Перший співмножник = -4

mov BL, 4; Другий співмножник = 4

imul BL; AX = FFFO = -16

Тут дія команд mul і imul над одними і тими ж операндами дає різні результати. У першому прикладі число без знака FCh, яке інтерпретується, як 252, множиться на 4, даючи в результаті число без знака 3F0, тобто 1008. У другому прикладі те ж число FCh розглядається, як число зі знаком. У цьому випадку воно складає -4. Множення на 4 дає FFF0h, тобто -16.