2. Повторение строковой инструкции
Для повторения строковой инструкции необходимое количество раз существует префикс REP (от английского REPEAT - повтор). Префикс инструкции изменяет работу последующей инструкции. Префикс REP делает следующее: он указывает, что последующую инструкцию нужно повторно выполнять до тех пор, пока содержимое регистра СХ (регистр – счетчик) не станет равным 0. (Если регистр СХ равен 0 в начале выполнения инструкции, то инструкция выполняется 0 раз, другими словами, никаких действий не производится. Этим команда REP отличается от команды организации цикла LOOP, которая при нулевом значении CX повторится 65535 раз, т.к. сначала происходит уменьшение, затем проверка.)
Префикс REP вызывает повторение только строковой инструкции.
Инструкция типа:
rep mov ax,[bx]
не имеет смысла. В этом случае префикс rep игнорируется и выполняется инструкция:
mov ax,[bx]
А инструкция
rep STOSB
выполнит запись из регистра AL в ячейки памяти, начиная с ячейки ES:DI, до адреса ES:DI + CX.
3. Поиск данных с помощью строковой инструкции
Инструкция SCAS
Инструкция SCAS используется для просмотра памяти и поиска совпадения или несовпадения с конкретным значением размером в байт или слово. Как и все строковые инструкции, инструкция SCAS имеет две формы - SCASB и SCASW.
Инструкция SCASB сравнивает содержимое регистра AL с байтовым значением по адресу ES:DI, устанавливая при этом флаги, отражающие результат сравнения (как при выполнении инструкции СМР). Как и при выполнении инструкции STOSB, при выполнении инструкции SCASB увеличивается или уменьшается значение регистра DI.
Строковые инструкции никогда не устанавливают флаги таким образом, чтобы они отражали изменения значений регистров SI, DI и/или СХ. Инструкции STOS и MOVS вообще не изменяют никаких флагов, а инструкции SCAS и CMPS изменяют флаги только в соответствии с результатом выполняемого ими сравнения.
Префикс rep распространяется так же и на команды поиска. Однако может оказаться желательным прекратить выполнение цикла в случае совпадения или несовпадения. Для этого существует две формы префикса REP, которые можно использовать с инструкцией SCAS (и с CMPS) - repE и repNE.
Префикс REPE (который также называется префиксом REPZ) указывает процессору, что инструкцию SCAS (или CMPS) нужно повторять до тех пор, пока регистр СХ не станет равным нулю, или пока не произойдет несовпадение. Префикс repE можно рассматривать, как префикс, означающий "повторять, пока равно". Аналогично, префикс REPNE (KEPNZ) указывает процессору, что инструкцию SCAS (CMPS) нужно повторять, пока СХ не станет равным нулю или пока не произойдет совпадения. Префикс KEPNE можно рассматривать, как префикс "повторять, пока не равно".
Как и все строковые инструкции, инструкция SCAS увеличивает регистр-указатель DI, если флаг направления равен 0 (очищен с помощью инструкции CLD), и увеличивает DI, если флаг направления равен 1 (установлен с помощью инструкции STD).
Инструкция SCASW - это форма инструкции SCASB для работы со словом. Она сравнивает содержимое регистра АХ с содержимым памяти по адресу ES:DI и увеличивает или уменьшает значение регистра DI в конце каждого выполнения на 2, а не на 1.
Инструкция CMPS
Инструкция CMPS позволяет выполнять сравнение двух байт или слов. При одном выполнении инструкции CMPS сравниваются две ячейки памяти, а затем увеличиваются регистры SI и DI. Инструкцию CMPS можно рассматривать, как аналог инструкции MOVS, который вместо копирования одной ячейки памяти в другую сравнивает две ячейки памяти.
Инструкция CMPSB сравнивает байт по адресу DS:SI с байтом по адресу ES:DI, устанавливая соответствующим образом флаги и увеличивая или уменьшая регистры SI и DI (в зависимости от флага направления). Регистр АL при этом не изменяется.
Инструкция CMPSW аналогична инструкции CMPSB, отличие состоит в том, что производится сравнение слов.
ЗАДАНИЕ №1
.data
L dd n/2-1 ;левая граница неотсортированного массива
R dd n-1 ;правая граница неотсортированного массива
.code
;массив преобразуется в отображение пирамиды - вызвать процедуру
;down_heap n/2 раз для преобразования массива в пирамиду
b0: call down_heap
dec L ;while ( L > 0 ) L--;
jnz short b0
;собственно пирамидальная сортировка
dec L ;L=0
dec R ;R=n-2
b1: mov edx,R ;отправляем значение максимального
mov eax,array ;элемента в конец массива
xchg eax,array[edx*4+4] ; array[0] <--> array[R];
mov array,eax
call down_heap ;восстанавливаем пирамиду - на ее
;вершине появляется новое максимальное значение
dec R ;уменьшаем индекс последнего элемента
jnz short b1 ;while ( R > 0 ) R--;
b2: ...
;-----------------------------------------------------
down_heap proc; процедура вставки элемента на свое место в пирамиду
mov eax,L
mov ebx,eax ;i = L;
shl eax,1 ;j = 2*L;
mov esi,array[eax*2] ;item = array[L];
cmp eax,R ;if( j<R && array[j] < array[j+1]) j++;
jnb short a0
mov edx,array[eax*4]
cmp edx,array[eax*4+4] ;array[j] < array[j+1] ?
jnb short a0
; условие j<R && array[j]<array[j+1] выполнилось
inc eax ;j++
a0: cmp eax,R ;while( j£R && item < array[j])
ja short a1
mov edi,array[eax*4]
cmp esi,edi ;item < array[j] ?
jnb short a1
; условие j<=R && item < array[j] выполнилось
mov array[ebx*4],edi ;array[i] = array[j];
mov ebx,eax ;i = j;
shl eax,1 ;j = 2*j;
cmp eax,R
jnb short a0;if( j<R && array[j] < array[j+1]) j++;
mov edx,array[eax*4]
cmp edx,array[eax*4+4]
jnb short a0
; условие j<R && array[j] < array[j+1] выполнилось
inc eax ;j++
jmp short a0
a1: mov array[ebx*4],esi ;array[i] = item;
retn
down_heap endp
ЗАДАНИЕ №2
masm
model small
.data
var1 db 12
.stack 256h
.code
main proc
mov ah,var1
mov ds:[0000h],ah
mov al,ds:[0000h]
mov ax,4c00h
int 21h
main endp
end main
Вывод: Получено освоение способов работы с памятью посредством строковых инструкций.