Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Тема 4.1  Команды управления циклами




 

Существует несколько команд условного перехода, предназначенных для управления циклами в программах. Поскольку программые циклы используются часто, желательно эффективное управление циклом.

Так же, как строковые команды используют регистр CX в качестве счетчика, команды цикла LOOP используют регистр CX в качестве счетчика цикла. Все эти команды неявно рассматривают регистр CX как счетчик итераций цикла. Простейшая команда среди них - команда LOOP. Команда LOOP уменьшает регистр CX и передает управление на метку, если содержимое регистра CX не равно 0. Если вычитание единицы из регистра CX не привело к нулевому результату, команда LOOP не делает перехода, и выполняется следующая команда[6].

Программа помещает число итераций цикла в регистр CX перед выполнением цикла. Затем выполняется тело цикла, а следом за ним команда LOOP. Она уменьшает счетчик на единицу, что соответствует единственной, только что выполненной итерации цикла. Если теперь счетчик в регистре CX равен 0, программа продолжает выполняться после команды LOOP. Если счетчик не равен 0, управление возвращается к началу цикла, чтобы совершить еще один проход по телу цикла. Тело цикла выполняется столько раз, сколько было сначала задано содержимым регистра CX. Единственное важное замечание: если программа внутри цикла изменяет регистр CX, число итераций цикла не будет соответствовать начальному значению в регистре CX.

Описанный метод одинаково хорошо работает, когда число циклов известно во время ассемблирования (как в примере, где LOOP_COUNT - непосредственно заносимое значение), и когда число циклов определяется во

время выполнения. Если вычисленное число оказалось равным 0, цикл выполнится 65536 раз. Когда микропроцессор 8088 выполняет первую команду LOOP, он уменьшает CX от 0 до 0FFFFH, и поскольку теперь регистр CX ненулевой, повторяет цикл. Таким образом, загрузка нулевого значения счетчика циклов - специальный случай. Этот специальный случай обрабатывается командой JCXZ (переход, если содержимое регистра CX равно 0). Эта команда проверяет текущее содержимое регистра CX, и делает переход, если оно равно нулю. Команда не проверяет ни одного флага, и не влияет ни на один из них. Следующий пример аналогичен предыдущему, за исключением того, что он загружает регистр CX из ячейки памяти, содержимое которой вычисляется во время выполнения программы. По этой причине может оказаться, что счетчик циклов нулевой, и пример использует команду JCXZ, чтобы проверить, нужно ли полностью пропустить тело цикла[7].

В программе не нужно использовать команду JCXZ в каждом цикле с вычисляемым счетчиком. Если программист знает, что счетчик циклов никогда не будет равен нулю, проверка не нужна. Однако опыт показывает, что значение, которое " никогда" не должно появиться, обычно появляется в первую очередь, как только вы начинаете выполнять программу.

Оставшиеся две команды цикла предоставляют еще большие возможностей при управлении циклами. Эти команды аналогичны префиксам REPE и REPNE. Если команда LOOP выходит из цикла, только когда в регистре CX оказывается нуль, то команда LOOPE (цикл, пока равно) выходит из цикла, если установлен флаг нуля, или если в регистре CX получился 0. Тем самым становится возможным двойственное завершение цикла. Программа может загрузить в регистр CX максимальное число итераций цикла, а затем проверять флаг нуля в конце каждого цикла на условие завершения. Команда LOOPNE (цикл, пока не равно) выполняет обратную к описанной проверку флага нуля: цикл здесь завершается, если регистр достиг нуля, или если установлен флаг нуля. Следующий пример показывает использование команды LOOPNE. В примере складываются два списка чисел, чтобы найти пару элементов, сумма которых точно равна 100. Так как в каждой итерации перед проверкой складываются два чила, команду REPNE CMPSB использовать нельзя.

Команды работы со строками работают с большими структурами данных в памяти, такими, как алфавитно-цифровые строки символов. Смотри также раздел, посвященный Вводу/Выводу, для получения более подробной информации относительно команд Ввода/Вывода строк (иногда их называют блочными командами Ввода/Вывода).

Работа со строками может выполняться посредством команд работы со строками (которые выполняют только одну итерацию для каждой операции) совместно с другими возможностями команд процессора, такими, как префиксы повторения. Команды работы со строками:

MOVS - Переслать строку;

CMPS - Сравнить строки;

SCAS - Сканировать строку;

LODS - Загрузить строку;

STOC - Запомнить строку.

После выполнения команды работы со строкой, регистры строки-источника и строки-приемника указывают на следующие элементы в этих строках. Эти регистры автоматически увеличивают или уменьшают свои значения на количество байт, занятых каждым элементом строки. Элементом строки может быть байт, слово или двойное слово.

Операции работы со строками могут начинаться со старших адресов и выполняться по направлению к младшим адресам, или могут начинаться с младших адресов и выполняться по направлению к старшим адресам.

Исключения и прерывания, которые могут возникать в процессе выполнения команд работы со строками, сохраняют регистры в таком состоянии, чтобы команда работы со строкой могла быть повторена. Регистры источника и приемника указывают на следующие элементы строк, регистр EIP указывает на команду работы со строкой и регистр ECX содержит значение, сохраненное в нем со времени последней успешной итерации. Все, что необходимо для повторного запуска операции - это обработать прерывание или зафиксировать источник исключения, затем выполнить команду IRET.

Префиксы повторения REP (Повторять, пока ECX не равен нулю), REPE/REPZ (Повторять пока равно/ноль) и REPNE/REPNZ (Повторять пока не равно/не ноль) задают повторяющееся выполнение команд работы со строками. Эта форма итераций позволяет операциям работы со строками работать быстрее, чем это возможно при организации программных циклов.

Когда у команды работы со строкой имеется префикс повторения, операция выполняется до тех пор, пока одно из условий окончания, определяемое префиксом, не будет выполнено.

Для каждого повторения команды работа со строкой может быть приостановлена прерыванием или исключением. После того, как прерывание или исключение было обработано, операция работы над строкой может быть продолжена с того места, на котором она была приостановлена. Этот механизм позволяет выполнять длинные операции над строками без влияния на время отклика системы на прерывание[8].

Префиксы повторения отличаются друг от друга по своим дополнительным условиям окончания работы. Префикс REP не имеет дополнительных условий окончания. Префиксы REPE/REPZ и REPNE/REPNZ используются исключительно с командами SCAS (Сканировать строку) и CMPS (Сравнить строки). Префикс REPE/REPZ заканчивает работу, если флаг ZF очищен. Префикс REPNE/REPNZ заканчивает работу, если флаг ZF установлен. Флаг ZF не требует предварительной инициализации перед выполнением повторяющихся команд работы со строками, так как и SCAS и CMPS воздействуют на флаг ZF в соответствие с результатами сравнения, которое они выполнили.

Хотя регистры общего назначения в большинстве случаев полностью взаимозаменяемы, команды работы со строками требуют использования двух

специальных регистров. Строки источника и приемника находятся в памяти, адресуемой регистрами ESI и EDI. Регистр ESI указывает на операнд-источник. По умолчанию, регистр ESI используется вместе с сегментным регистром DS. Префикс замены сегмента позволяет использовать регистр ESI вместе с сегментными регистрами CS, SS, ES, FS или GS. Регистр EDI указывает на операнд назначения. Он использует сегмент, на который который указывает сегментный регистр ES; замена этого сегмента запрещена. Использование двух различных сегментных регистров в одной команде позволяет работать со строками, расположенными в различных сегментах.

Когда в командах работы со строками используются регистры ESI и EDI, они автоматически увеличиваются или уменьшаются после каждой итерации. Действия над строками можно начинать выполнять со старших адресов по направлению к младшим адресам, или они могут выполняться, начиная с младших адресов по направлению к старшим адресам.

Направление операций управляется флагом DF. Если флаг очищен, значения регистров увеличиваются. Если флаг установлен, значения регистров уменьшаются. Команды STD и CLD устанавливают и очищают этот флаг.

MOVS (Переслать строку) перемещает элемент строки, адресуемый регистром ESI в позицию, адрес которой указан в регистре EDI. Команда MOVEB перемещает байты, команда MOVEW перемещает слова и команда MOVED перемещает двойные слова. Команда MOVE, когда она дополнена префиксом REP, работает как пересылка блоков из памяти в память. Для выполнения этой операции программа должна инициализировать регистры ECX, ESI и EDI. Регистр ECX указывает количество элементов в блоке.

CMPS (Сравнение строк) вычитает элемент строки-приемника из элемента строки-источника и обновляет флаги AF, SF, PF, CF и OF. Ни один из элементов не будет записан обратно в память. Если элементы строки равны, устанавливается флаг ZF; в противном случае этот флаг очищается. CMPSB сравнивает байты, CMPSW сравнивает слова и CMPSD сравнивает двойные слова.

SCAS (Сканировать строку) вычитает элемент строки-приемника из регистра EAX, AX или AL (в зависимости от длины операнда) и обновляет флаги AF, SF, ZF, PF и OF. Строка и регистры не изменяются. Если значения равны, устанавливается флаг ZF; в противном случае флаг очищается. Команда SCASB сканирует байты, команда SCASW сканирует слова и команда SCASD сканирует двойные слова. Когда префиксы REPE/REPZ или REPNE/REPNZ модифицируют команду SCAS или CMPS, сформированный при этом цикл заканчивается либо по счетчику цикла, либо по тому воздействию, которое команды SCAS или CMPS оказывают на флаг ZF.

LODS (Загрузить строку) помещает элемент строки-источника, на который указывает адрес в регистре ESI, в регистр EAX для строк из двойных слов, в регистр AX для строк из слов или в регистр AL для строк из байтов. Эта команда используется обычно внутри цикла, где другие команды обрабатывают каждый элемент строки по мере его появления в регистре. STOS (Запомнить строку) помещает элемент строки из регистра EAX, AX или AL в строку, на которую указывает адрес в регистре EDI. Эта команда обычно используется в цикле, где она записывает в память результат обработки элемента строки, считанного из памяти при помощи команды LODS. Команда REP'STOS является самым быстрым способом инициализации большого блока памяти[9].

Для вывода данных на экран можно использовать два вида функций: универсальную функцию 40h (вывод в файл) и группу специализированных функций MS DOS вывода на экран.

Вывод символа на экран (02h int 21h). Функция 02h позволяет вывести один символ на экран.

Вход: АН > > 02h - вывод символа;

DL = символ для вывода.

Функция 02h проверяет наличие в клавиатурном буфере символов нажатия комбинации CTRL + C (CTRL + Break), при обнаружении которых производится вызов прерывания int 23h. В процессе вывода функция реагирует на управляющие символы, такие как 0dh (возврат каретки), 0ah (перевод строки), 08h (курсор назад на один символ), 07h (звуковой сигнал) и т. д.

Прямой вывод символа на экран (06h int 21h).

Функция 06h выводит один символ на экран. Эта функция универсальна, так как используется и для ввода и для вывода символа.

Вход: АН = 06h - вывод символа на экран;

DL = символ для вывода (за исключением 0ffn).

Функция 06h не проверяет наличие в буфере символов нажатия комбинации CTRL + C (CTRL + Break). Порядок использования данной функции аналогичен порядку использования функции 02h.

Вывод строки на экран (09h int 21h)

Функция 09h выводит строку символов на экран. Строка должна обязательно заканчиваться символом $. Данную функцию удобно использовать для вывода на экран различных диагностических сообщений. Если требуется организовать вывод строк, длина которых формируется динамически, то лучше либо использовать упомянутую выше функцию 40h, либо выводить их в цикле, тело которого содержит одну из функций 02h или 06h.

Вход: АН = 09h - вывод строки на экран;

DS: DX - адрес строки для вывода с завершающим символом $.

Функция 09h проверяет наличие в клавиатурном буфере символов нажатия комбинации CTRL + C (CTRL + Break), при обнаружении которых производится вызов прерывания int 23h. В процессе вывода функция реагирует на управляющие символы, такие как 0dh (возврат каретки), 0ah (перевод строки), 08h (курсор назад на один символ), 07h (звуковой сигнал) и т. д.

 

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...