Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции / Лекция 6 / Лекция 6.doc
Скачиваний:
24
Добавлен:
10.06.2015
Размер:
226.3 Кб
Скачать

Команды условного перехода и регистр есх/сх

Архитектура процессора предполагает специфическое использование многих регистров. К примеру, регистр EAX/AX/AL используется как аккумулятор, а регистры ЕВР/ВР, ESP/SP для работы со стеком. Регистр ЕСХ/СХ тоже имеет определенное функциональное назначение — он выполняет функции счетчика в командах управления циклами и при работе с цепочками символов. Возможно, что функционально команды условного перехода, связанные с регистром ЕСХ/СХ, правильнее было бы отнести к этой группе команд.Синтаксис команд JCXZ (Jump if ex is Zero — переход, если СХ ноль) и J ECXZ (Jump Equal ecx Zero — переход, если ЕСХ ноль) таков:

j c x z / j e c x z метка_перехода

Эти команды очень удобно использовать при организации цикла и при работе с цепочками символов. В этой главе мы разберемся со средствами организации циклов в программах на языке ассемблера и покажем работу команд JCXZ/JECXZ. Глава 12 будет посвящена цепочечным командам, где мы еще раз вернемся к командам JCXZ/JECXZ. Нужно отметить свойственное им ограничение. В отличие от других команд условной передачи управления, команды JCXZ/J ECXZ могут адресовать только короткие переходы на -128 байт или на +127 байт от следующей за ней команды.

Установка байта по условию

При рассмотрении команд условного перехода логично упомянуть еще об одной команде SETcc. Данная команда впервые появилась в процессоре 1386.

Ее формат:

SETcc операнд1

Команда устанавливает байт операнд! после проверки модификатора ее, задающего условие, аналогично тому, как это делается в командах условного перехода. Фактически, модификатор ее обозначает флаг, который нужно проверить (см. приложение). В качестве операнда используется либо один из 8-разрядных регистров (AL, АН, BL, BH, CL, CH, DL, DH), либо адрес ячейки памяти размером в байт. Алгоритм работы команды заключается в том, что значение операнда устанавливается по результатам проверки условия, заданного модификатором сc:

-операнд1 = 0 — если условие ложно;

-операнд1 = 1 — если условие истинно.

К примеру, в следующем фрагменте байт по адресу rez будет установлен в 0:

mov ах,0

crop ax,1

sete byte ptr rez

Организация циклов

Цикл, как известно, представляет собой важную алгоритмическую структуру, без которой не обходится, наверное, ни одна программа. Организовать циклическое выполнение некоторого фрагмента программы можно, к примеру, используя команды условной передачи управления или команду безусловного перехода JMP. Например, подсчитаем количество нулевых байтов в области mas (листинг 10.2).

Листинг 10.2. Подсчет числа нулевых элементов

<1> ;prg_10_2.asm

<2> model small

<3> .stack 100h

<4> .data

<5> len equ 10 ;количество элементов в mas

<6> mas db 1,0,9,8,0,7,8,0,2,0

<7> .code

<8> start:

<9> mov ax @data

<10> mov ds

<11>movcxlen ;длину поля mas в сх

<12> xor ax ax

<13> xor si si

<14> cycl:

<15> jcxz exit ;проверка сх на 0, если 0, то выход

<16> cmp mas[si],0 ;сравнить очередной элемент mas с 0

<17> jne ml ;если не равно 0, то на ml

<18> inc al ;в al - счетчик нулевых элементов

<19> ml:

<20> inc si ;перейти к следующему элементу

<21> dec сх уменьшить сх на 1

<22> jmp cycl

<23> exit:

<24> mov ax,4c00h

<25> int 21h ;возврат управления операционной системе

<26> end start

Цикл в листинге 10.2 организован тремя командами, JCXZ, DEC и JMP (строки 15, 21 и 22). Команда JCXZ выполняет здесь две функции: предотвращает выполнение «пустого» цикла (когда счетчик цикла в СХ равен нулю) и отслеживает окончание цикла после обработки всех элементов поля mas. Команда DEC после каждой итерации цикла уменьшает значение счетчика в регистре СХ на 1. Заметьте, что при такой организации цикла все операции по его организации выполняются «вручную». Но, учитывая важность такого алгоритмического элемента, как цикл, разработчики процессора ввели в систему команд группу из трех команд, облегчающую программирование циклов. Эти команды также используют регистр ЕСХ/СХ как счетчик цикла. Дадим краткую характеристику этим командам.

Команда LOOP позволяет организовать циклы (loops), подобные циклам for в языках высокого уровня с автоматическим уменьшением счетчика цикла. Синтаксис команды:

loop метка_перехода

Команда реализует описанные далее действия.

1. Декремент регистра ЕСХ/СХ.

2. Сравнение регистра ЕСХ/СХ с нулем:

-если (ЕСХ/СХ) > 0, то управление передается на метку перехода;

-если (ЕСХ/СХ) = 0, то управление передается на следующую после LOOP команду.

Команды LOOPE и LOOPZ (Loop still сх <> 0 or Zero flag = 0 — повторить цикл пока СХ <> 0 или ZF = 0) — абсолютные синонимы, поэтому используйте ту команду, которая вам больше нравится. Синтаксис команд:

loope/loopz метка_перехода

Команды реализуют описанные далее действия.

1. Декремент регистра ЕСХ/СХ.

2. Сравнение регистра ЕСХ/СХ с нулем и анализ состояния флага нуля ZF:

-если (ЕСХ/СХ) > 0 и ZF = 1, управление передается на метку перехода;

-если (ЕСХ/СХ) = 0 или ZF=0, управление передается на следующую после LOОР команду.

Команды LOOPNE и LOOPNZ (Loop still ex <> 0 or NonZero flag = 0 — повторить цикл, пока СХ <> 0 или ZF = 1) также абсолютные синонимы. Синтаксис команд:

loopne/loopnz метка_перехода

Команды реализуют описанные далее действия.

1. Декремент регистра ЕСХ/СХ.

2. Сравнение регистра ЕСХ/СХ с нулем и анализ состояния флага нуля ZF:

- если (ЕСХ/СХ) > 0 и ZF = 0, управление передается на метку перехода;

- если (ЕСХ/СХ) = 0 или ZF = 1, управление передается на следующую после LOOP команду.

Команды LOOPE/LOOPZ и LOOPNE/LOOPNZ по принципу своей работы являются

взаимнообратными. Они расширяют действие команды LOOP тем, что дополнительно анализируют флаг ZF. Это дает возможность организовать досрочный выход из цикла, используя этот флаг в качестве индикатора. Типичное применение этих команд связано с операцией поиска определенного значения в последовательности или со сравнением двух чисел.

Недостаток команд организации цикла LOOP, LOOPE/LOOPZ и LOOPNE/LOOPNZ заключается в том, что они реализуют только короткие переходы (от -128 до +127 байт). Для работы с длинными циклами придется использовать команды условного перехода и команду JMP (см. листинг 10.2), поэтому постарайтесь освоить оба способа организации циклов. Рассмотрим несколько примеров организации циклов с помощью команд LOOP, LOOPE/LOOPZ и LOOPNE/LOOPNZ.

Программа из листинга 10.2 с использованием команды организации цикла будет выглядеть так, как показано в листинге 10.3.

Листинг 10.3. Подсчет нулевых байтов с использованием команд

управления циклом

<1> ;prg_10_3.asm

<2> model small

<3> .stack 100h

<4> .data

<5> len equ 10 ;количество элементов в mas

<6> mas db 1,0.9,8.0.7,8,0,2,0

<7> .code

<8> start:

<9> mov ax,@data

<10> mov ds.ax

<11> mov ex,len ;длину поля mas в сх

<12> xor ax,ax

<13> xor si,si

<14> jcxz exit ;проверка сх на 0, если 0, то выход

<15> cycl:

<1б> cmp mas[si],0 ;сравнить очередной элемент mas с 0

<17> jne ml ;если не равно 0, то на ml

<18> inc al ;в al - счетчик нулевых элементов

<19> ml:

<20> inc si ;перейти к следующему элементу

<21> loop cycl

<22> exit:

<23> mov ax,4c00h

<24> int 21h ;возврат управления операционной системе

<25> end start

Заметьте, что у команды JCXZ в строке 14 осталась только одна функция — не допустить выполнения «пустого» цикла, поэтому несколько изменилось ее место в тексте программы: теперь она стоит перед меткой начала цикла cycl. Изменение и контроль содержимого регистра СХ в процессе выполнения каждой итерации выполняет команда LOОР (строка 21).

Рассмотрим пример, в котором продемонстрируем типичный подход к использованию команды LOOPNZ. В программе из листинга 10.4 ищется первый нулевой элемент в поле mas. Интерес представляют строки 20 и 21. Команда LOOPNZ на основании содержимого регистра СХ и флага ZF принимает решение о продолжении цикла. Выход из цикла происходит в одном из двух случаев: СХ = 0 (просмотрены все элементы поля mas) или ZF = 1 (командой СМР обнаружен нулевой элемент). Назначение следующей команды JZ (строка 21) в том, чтобы распознать конкретную причину выхода из цикла. Если выход из цикла произошел после просмотра строки, в которой нет нулевых элементов, то флаг JZ не сработает и будет выдано сообщение об отсутствии нулевых элементов в строке (строки 7, 23-25). Если выход из цикла произошел в результате обнаружения нулевого элемента, то в регистре SI окажется номер позиции этого элемента в поле mas и при необходимости можно продолжить обработку. В нашем случае мы просто завершаем программу переходим на метку exit.

Листинг 10.4. Пример использования команды loopnz

<1> ;prg_10_4.asm

<2> model small

<3> .stack 100h

<4> .data

<5> len equ 10 ;количество элементов в mas

<6> mas db 1,0,9,8,0,7,8,0,2,0

<7> message db "В поле mas нет элементов, равных нулю,$"

<8> .code

<9> start:

<10> mov ax,@data

<11> mov ds.ax

<12> mov ex,len ;длину поля mas в сх

<13> xor ax,ax

<14> xor si,si

<15> jcxz exit ;проверка сх на 0, если 0, то выход

<1б> mov si,-l ;готовим si к адресации элементов поля mas

<17> cycl:

<18> inc si

<19> cmp mas[si],0 ;сравнить очередной элемент mas с 0

<20> loopnz cycl

<21> jz exit;выяснение причины выхода из цикла

<22> ;вывод сообщения, если нет нулевых элементов в mas

<23> mov ah,9

<24> mov dx,offset message

<25> int 21h

<26> exit:

<27> mov ax,4c00h

<28> int 21h ;возврат управления операционной системе

<29> end start

Читатели, имеющие даже небольшой опыт программирования на языках высокого уровня, знают, что очень часто возникает необходимость во вложенных циклах. Самый простой пример — обработка двухмерного массива. Работу с массивами, в том числе двухмерными, мы рассмотрим в главе 13, пока же разберемся с основными принципами организации вложенных циклов. Основная проблема, которая при этом возникает, — как сохранить значения счетчиков в регистре ЕСХ/СХ для каждого из циклов. Для временного сохранения счетчика внешнего цикла на время выполнения внутреннего доступно несколько способов: задействовать регистры, ячейки памяти или стек. В следующем фрагменте программы имеется три цикла, вложенные один в другой. Этот фрагмент можно рассматривать как шаблон для построения других программ с вложенными циклами.

<1>…

<2> mov сх,100 количество повторений цикла cycl_l

<3> cycl_l:

<4> push сх ;счетчик цикла cycl_l в стек

<5> ;... команды цикла cycl_l

<6> mov сх,50 количество повторений цикла cycl_2

<7> cycl_2:

<8> push сх ;счетчик цикла cycl_2 в стек

<9> ;...;команды цикла cycl_2

<10> mov сх,25 количество повторений цикла cycl_3

<11> cycl_3:

<12> ;...команды цикла cycl_3

<13> loop cycl_3

<14> ;...команды цикла cycl_2

<15> pop сх восстановить счетчик цикла cycl_2

<1б> loop cycl_2

<17> ;...команды цикла cycl_l

<18> pop сх восстановить счетчик цикла cycl_l

<19> loop cycl_l

<20> ;...

В качестве примера рассмотрим фрагмент программы, которая обрабатывает специальным образом некоторую область памяти (листинг 10.5). Область памяти рассматривается как совокупность пяти полей, содержащих 10 однобайтовых элементов. Требуется заменить все нулевые байты в этой области значением Offh.

Листинг 10.5. Пример использования вложенных циклов

<1> ;prg_10_5.asm

<2> model small

<3> .stack 100h

<4> .data

<5> mas db 1,0,9,8,0,7,8

<6>db 1,0,9,8,0,7,8

<7>db 1,0,9,8,0 7 8

<8>db 1 0,9,8,0 7 R

<9>db1,0,9,8,0,7,8,0,2

<10>. code

<11>start:

<12>mov ax,@data

<13>mov ds.ax

<14>xor ax, ax

<15>lea bx.mas

<16>mov ex, 5

<17>cycl_l:

<18>push ex

<19>xor si , si

<20>mov

<21>cycl_2:

<22>сmр byte ptr [bx+si] ,0

<23>jne no zero

<24>mov byte ptr [bx+si] ,0ffh

<25>no_zero:

<26>inc si

<27>loop cycl_2

<28>pop cx

<29>add bx,10

<30>loop cycl_l

<31>exit:

<32>mov ax,4c00h

<33>int21h ;возврат управления операционной системе

<24>end start

Соседние файлы в папке Лекция 6