лабораторные на Pasca (Кудрявцев)l
.pdf
|
Встроенный ассемблер |
333 |
||
|
|
|
|
|
|
|
|
|
|
|
|
Команды управления циклами |
|
|
|
|
|
|
|
|
LOOP |
LOOP близкая метка |
Повторить цикл |
|
|
|
|
|
|
|
LOOPE/LOOPZ |
LOOPE близкая метка |
Повторять, пока равны |
|
|
|
|
|
|
|
LOOPNE/LOOPNZ |
LOOPNE близкая метка |
Повторять, пока не равны |
|
|
|
|
|
|
Команды безусловных переходов CALL, RET, JMP могут использо- вать дальнюю или ближнюю модель памяти, в то время как коман- ды условных переходов – только малую (в пределах –128...+127 байтов). При дальней модели памяти (устанавливается опцией
Options/Compiler/Force far calls среды Турбо Паскаля или директивой
компилятора {F+}) осуществляется как внутрисегментная, так и межсегментная передача управления, при ближней – только внут- рисегментная.
Инструкция CALL работает следующим образом. Вначале ад- рес следующей за CALL инструкции (адрес возврата) помещается в стек, затем в регистр IP (или в пару CS:IP) помещается адрес точки входа в процедуру, таким образом сразу за командой CALL будет исполняться уже первая команда процедуры. Оба адреса (точки входа и возврата) будут 16-битовыми смещениями для внутрисег- ментного вызова или 32-битовыми полными адресами – для меж- сегментного. Все процедуры (функции) Паскаля, оттранслирован- ные в режиме {F+} или содержащие зарезервированное слово FAR в заголовке, должны вызываться как дальние. Для этого за инструк- цией CALL следует указать модель памяти:
Procedure MyProc; Far;
……
Asm
call FAR MyProc |
{Вызов дальней процедуры} |
end; |
|
Таким же способом должны вызываться все библиотечные подпро- граммы (т.е. объявленные в интерфейсных частях модулей). При
дальнем вызове в стек сначала заталкивается содержимое сегмента кода CS, а уже затем – смещение возврата.
При выходе из дальней процедуры команда RET извлекает из стека оба 16-разрядных слова и помещает первое в IP, а второе в CS, а при выходе из ближней извлекает из стека только смещение и по- мещает его в IP.
334 |
Приложение |
|
|
Команды условных переходов способны передавать управление на метку, расположенную в пределах ближайших плюс–минус 128 байт от самой команды. Если нужно передать управление на метку, расположенную дальше в том же сегменте, или на метку в другом сегменте, сразу: а командой условной передачи располагают безус- ловную команду JMP или CAL, например:
cmp ах, 0 |
{Проверяем АХ} |
jne @NotZero |
{AX=0 ?} |
jmp IsZero |
{Да - переходим на дальнюю метку} ..... |
…… |
{Нет - продолжаем работу} |
…… |
|
В таблице термин «выше/ниже» используется применительно к сравнению беззнаковых операндов, а «больше/меньше» – знаковых.
Поскольку условные переходы реализуют ветвление программы на основе проверки флагов, обычно непосредственно перед ними рас- полагаются команды, изменяющие эти флаги, чаще всего – команда сравнения СМР. Ниже показаны комбинации СМР–условный пере- ход для различных соотношений приемника и источника (первого и второго операнда) команды СМР:
Условие |
Для беззнаковых |
Для чисел |
|
чисел |
со знаками |
||
|
|||
Приемник больше источника |
JA |
JG |
|
Приемник и источник равны |
JE |
JE |
|
Приемник меньше источника |
JB |
JL |
|
|
|
|
|
Приемник не меньше источника |
JAE |
JGE |
|
Приемник не больше источника |
JBE |
JLE |
|
Приемник и источник не равны |
JNE |
JNE |
Например:
cmp ах, 5 |
{AX>5 ?} |
ja @Above5 |
{Да, больше – переходим} |
cmp bx, -3 |
{ВХ<= -3 ?} |
jle@LessM3 |
{Да, меньше или равен} |
Команды LOOP/LOOPE/LOOPNE служат для организации циклов. Все они используют содержимое регистра СХ как счетчик числа повторений. Команда LOOP уменьшает СХ на единицу и передает управление на метку начала цикла, если содержимое этого регистра
Встроенный ассемблер |
335 |
|
|
отлично от нуля. Команды LOOPE/LOOPNE также уменьшают счет- чик СХ, но передают управление в начало цикла при совместном условии установки (или сброса) флага ZF и неравенства нулю счет- чика СХ.
Вот как, например, можно отыскать нулевой байт в массиве АОВ:
Var
АОВ: array [1..1000] of Byte;
……
Asm
mov сx, 1000 |
|
{Инициируем счетчик СХ} |
lea bx, AOB |
|
{Помещаем адрес АОВ в BX} |
dec bx |
|
{Готовим цикл} |
|
{Здесь начало цикла проверки} |
|
(@Test: inc bx |
|
{Адрес очередного байта} |
cmp BYTE PTR |
[bx], 0 |
{Проверяем байт} |
loopne @Test |
|
{Замыкаем цикл} |
jnz @NotZero |
|
{Если не найден нулевой байт} |
…… |
|
{Нашли нулевой байт} |
end;
Строковые команды
Мнемоника |
Формат |
|
Комментарий |
|
|
|
|
|
Пересылка строк |
|
|
|
|
|
|
MOVSB |
MOVSB |
|
Пересылать байты |
MOVSW |
MOVSW |
|
Пересылать слова |
|
Сравнение строк |
|
|
|
|
|
|
CMPSB |
CMPSB |
|
Сравнивать байты |
CMPSW |
CMPSW |
|
Сравнивать слова |
|
Сканирование |
|
|
|
|
|
|
SCASB |
SCASB |
|
Искать байт |
SCASW |
SCASW |
|
Искать слово |
|
Загрузка и сохранение |
|
|
|
|
|
|
LODSB |
LODSB |
|
Загружать байты |
LODSH |
LODSW |
|
Загружать слова |
STOSB |
STOSB |
|
Сохранять байты |
STOSW |
STOSW |
|
Сохранять слова |
Строковые команды рассчитаны на обработку строк. Заметим, что термин «строка» здесь отнюдь не эквивалентен аналогичному тер- мину Турбо Паскаля и означает произвольную цепочку байт или слов длиной до 64 Кбайт. Эти команды оперируют пятью примити-
336 |
Приложение |
|
|
вами, каждый из которых обрабатывает лишь один байт или одно слово за раз. Перед примитивом обычно указывается префикс по- вторения REP/REPE/REPNE, заставляющий выполняться примитив до тех пор, пока не обнулится счетчик повторений СХ или не будет нарушено соответствующее условие.
При использовании строковых команд важно помнить два обстоя- тельства. Во-первых, эти команды всегда берут адрес строки- источника из пары DS:SI, а строки-приемника – из пары ES:DI. Та- ким образом, перед исполнением строковой команды необходимо инициировать сегментные регистры нужным образом. Во-вторых, строковые команды используют индексную адресацию с автомати- ческим изменением смещения в SI/DI после однократного исполне- ния примитива. Содержимое этих регистров изменяется на 1 при обработке байтов и на 2 при обработке слов, причем наращивается, если флаг направления DF сброшен, и уменьшается, если он равен
1.
Вот как можно осуществить пересылку массива А в массив В:
Var
А, В: array [1..250] of Integer;
……
Asm
lea si, A |
{Смещение А - в SI (источник)} |
push ds |
{Инициируем ES := DS} |
pop es |
|
lea di, B |
{Смещение В - в DI (приемник)} |
mov ex, 250 |
{Счетчик переноса} |
Сld |
{Направление переноса - наращивать} |
rep movsw |
{Переносим 500 байт} |
end; |
|
В программе на Турбо Паскале регистр DS всегда содержит сегмент данных, поэтому инициировать его необязательно. Что касается ре- гистра дополнительного сегмента ES, такого правила нет, и хотя в большинстве случаев он также ссылается на сегмент данных, реко- мендуется проводить его инициацию перед использованием стро- ковой команды (см. выше команды push ds, pop es).
Встроенный ассемблер |
337 |
|
|
Команды прерываний
Мнемоника |
Формат |
Комментарий |
|
|
|
INT |
INT номер |
Выполнить прерывание |
|
|
|
INTO |
INTO |
Выполнить прерывание по переполнению |
|
|
|
IRET |
IRET |
Вернуться из прерывания |
|
|
|
Выполнение прерываний во многом напоминает косвенный вызов дальней процедуры. По команде INT (INTO) в стек помещается ре- гистр флагов, сегмент CS и указатель IP, а новые значения этих ре- гистров берутся из 4-байтного вектора прерывания, соответствую- щего номеру прерывания в команде INT, или из вектора 4 – для ко- манды INTO. Таким образом, единственным отличием от команды CALL является то, что в стек предварительно заносится регистр флагов. Следует, правда, оговориться: перед передачей управления программе обработки прерывания микропроцессор сбрасывает фла- ги трассировки TF и прерываний IF; сброс TF необходим для обес- печения нормальной работы отладчиков, использующих прерыва- ние по вектору 1 или 4, сброс IF блокирует вмешательство других процессов в ход обработки прерывания.
Команда INTO представляет собой условное прерывание и выпол- няется, если в этот момент взведен флаг переполнения OF. Команда IRET реализует правильный выход из программы обработки преры- вания: она считывает из стека 3 двухбайтные слова и помещает их в регистры IP, CS и регистр флагов.
Команды управления
Мнемоника |
Формат |
Комментарий |
|
|
|
|
Управление флагами |
|
|
|
|
STC |
STC |
Установить перенос |
CLC |
CLC |
Очистить перенос |
CMC |
CMC |
Инвертировать CF |
STD |
STD |
Установить направление |
CLD |
CLD |
Очистить направление |
STI |
STI |
Разрешить прерывания |
CLI |
CLI |
Запретить прерывания |
|
Внешняя синхронизация |
|
|
|
|
HLT |
HLT |
Остановить вычисления |
WAIT |
WAIT |
Ждать активности на шине |
ESC |
ESC код, источник |
Передать команду |