4503

Цепочечные команды в языке ассемблер

Лабораторная работа

Информатика, кибернетика и программирование

Цепочечные команды в языке ассемблер Эти команды также называют командами обработки строк символов. Названия почти синонимичны. Отличие в том, что под строкой символов здесь понимается последовательность байт, а цепочка — это более общее назван...

Русский

2012-11-21

63.95 KB

51 чел.

Цепочечные команды в языке ассемблер

Эти команды также называют командами обработки строк символов. Названия почти синонимичны.

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

Таким образом, цепочечные команды позволяют проводить действия над блоками памяти, представляющими собой последовательности элементов следующего размера:

  1.  8 бит — байт;
  2.  16 бит — слово;
  3.  32 бита — двойное слово.

Содержимое этих блоков для микропроцессора не имеет никакого значения. Это могут быть символы, числа и все что угодно. Главное, чтобы размерность элементов совпадала с одной из перечисленных и эти элементы находились в соседних ячейках памяти.

Всего в системе команд микропроцессора имеется семь операций-примитивов обработки цепочек.

Каждая из них реализуется в микропроцессоре тремя командами, в свою очередь, каждая из этих команд работает с соответствующим размером элемента — байтом, словом или двойным словом.

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

Перечислим операции-примитивы и команды, с помощью которых они реализуются, а затем подробно их рассмотрим:

  1.  пересылка цепочки:

movs адрес_приемника,адрес_источника 

movsb 

movsw 

movsd

  1.  сравнение цепочек:

cmps адрес_приемника,адрес_источника 

cmpsb 

cmpsw 

cmpsd

  1.  сканирование цепочки:

scas адрес_приемника 

scasb 

scasw 

scasd

  1.  загрузка элемента из цепочки:

lods адрес_источника 

lodsb 

lodsw 

lodsd

  1.  сохранение элемента в цепочке:

stos адрес_приемника 

stosb 

stosw 

stosd

  1.  получение элементов цепочки из порта ввода-вывода:

ins адрес_приемника,номер_порта 

insb 

insw 

insd

  1.  вывод элементов цепочки в порт ввода-вывода:

outs номер_порта,адрес_источника 

outsb 

outsw 

outsd

Логически к этим командам нужно отнести и так называемые префиксы повторения. Вспомните формат машинной команды и его первые необязательные байты префиксов. Один из возможных типов префиксов — это префиксы повторения. Они предназначены для использования цепочечными командами.

Префиксы повторения имеют свои мнемонические обозначения:

rep 

repe или repz 

repne или repnz

Эти префиксы повторения указываются перед нужной цепочечной командой в поле метки.

Цепочечная команда без префикса выполняется один раз. Размещение префикса перед цепочечной командой заставляет ее выполняться в цикле.

Отличия приведенных префиксов в том, на каком основании принимается решение о циклическом выполнении цепочечной команды: по состоянию регистра ecx/cx или по флагу нуля zf:

  1.  префикс повторения rep (REPeat). Этот префикс используется с командами, реализующими операции-примитивы пересылки и сохранения элементов цепочек — соответственно, movs и stos.
  2.  Префикс rep заставляет данные команды выполняться, пока содержимое в ecx/cx не станет равным 0.
  3.  При этом цепочечная команда, перед которой стоит префикс, автоматически уменьшает содержимое ecx/cx на единицу. Та же команда, но без префикса, этого не делает;
  4.  префиксы повторения repe или repz (REPeat while Equal or Zero). Эти префиксы являются абсолютными синонимами.
  5.  Они заставляют цепочечную команду выполняться до тех пор, пока содержимое ecx/cx не равно нулю или флаг zf равен 1.
  6.  Как только одно из этих условий нарушается, управление передается следующей команде программы. Благодаря возможности анализа флага zf, наиболее эффективно эти префиксы можно использовать с командами cmps и scas для поиска отличающихся элементов цепочек.
  7.  префиксы повторения repne или repnz (REPeat while Not Equal or Zero). Эти префиксы также являются абсолютными синонимами. Их действие на цепочечную команду несколько отличается от действий префиксов repe/repz. Префиксы repne/repnz заставляют цепочечную команду циклически выполняться до тех пор, пока содержимое ecx/cx не равно нулю или флаг zf равен нулю.
  8.  При невыполнении одного из этих условий работа команды прекращается.
  9.  Данные префиксы также можно использовать с командами cmps и scas, но для поиска совпадающих элементов цепочек.

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

Цепочка-источник, адресуемая операндом адрес_источника, может находиться в текущем сегменте данных, определяемом регистром ds.

Цепочка-приемник, адресуемая операндом адрес_приемника, должна быть в дополнительном сегменте данных, адресуемом сегментным регистром es.

Важно отметить, что допускается замена (с помощью префикса замены сегмента) только регистра ds, регистр es подменять нельзя.

Вторые части адресов - смещения цепочек — также находятся в строго определенных местах.

Для цепочки-источника это регистр esi/si (Source Index register — индексный регистр источника).

Для цепочки-получателя это регистр edi/di (Destination Index register - индексный регистр приемника).

Таким образом, полные физические адреса для операндов цепочечных команд следующие:

  1.  адрес_источника — пара ds:esi/si;
  2.  адрес_приемника — пара es:edi/di.

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

В каждом из этих наборов присутствует одна команда с явным указанием операндов и три команды, не имеющие операндов.

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

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

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

Последний важный момент, касающийся всех цепочечных команд, — это направление обработки цепочки. Есть две возможности:

  1.  от начала цепочки к ее концу, то есть в направлении возрастания адресов;
  2.  от конца цепочки к началу, то есть в направлении убывания адресов.

Как мы увидим ниже, цепочечные команды сами выполняют модификацию регистров, адресующих операнды, обеспечивая тем самым автоматическое продвижение по цепочке. Количество байт, на которые эта модификация осуществляется, определяется кодом команды. А вот знак этой модификации определяется значением флага направления df (Direction Flag) в регистре eflags/flags:

  1.  если df = 0, то значение индексных регистров esi/si и edi/di будет автоматически увеличиваться (операция инкремента) цепочечными командами, то есть обработка будет осуществляться в направлении возрастания адресов;
  2.  если df = 1, то значение индексных регистров esi/si и edi/di будет автоматически уменьшаться (операция декремента) цепочечными командами, то есть обработка будет идти в направлении убывания адресов.

Состоянием флага df можно управлять с помощью двух команд, не имеющих операндов:

cld (Clear Direction Flag) — очистить флаг направления. Команда сбрасывает флаг направления df в 0.

std (Set Direction Flag) — установить флаг направления. Команда устанавливает флаг направления df в 1.

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

Операция пересылки цепочек

Команды, реализующие эту операцию-примитив, производят копирование элементов из одной области памяти (цепочки) в другую. Размер элемента определяется применяемой командой.

Система команд TASM предоставляет программисту четыре команды, работающие с разными размерами элементов цепочки:

movs адрес_приемника,адрес_источника (MOVe String) — переслать цепочку;

movsb (MOVe String Byte) — переслать цепочку байт;

movsw (MOVe String Word) — переслать цепочку слов;

movsd (MOVe String Double word) — переслать цепочку двойных слов.

Команда movs:

movs адрес_приемника,адрес_источника 

Команда копирует байт, слово или двойное слово из цепочки, адресуемой операндом адрес_источника, в цепочку, адресуемую операндом адрес_приемника.

Размер пересылаемых элементов ассемблер определяет, исходя из атрибутов идентификаторов, указывающих на области памяти приемника и источника. К примеру, если эти идентификаторы были определены директивой db, то пересылаться будут байты, если идентификаторы были определены с помощью директивы dd, то пересылке подлежат 32-битовые элементы, то есть двойные слова.

Ранее уже было отмечено, что для цепочечных команд с операндами, к которым относится и команда пересылки movs адрес_приемника,адрес_источника, не существует машинного аналога.

При трансляции в зависимости от типа операндов транслятор преобразует ее в одну из трех машинных команд:

movsb, movsw или movsd.

Сама по себе команда movs пересылает только один элемент, исходя из его типа, и модифицирует значения регистров esi/si и edi/di. Если перед командой написать префикс rep, то одной командой можно переслать до 64 Кбайт данных (если размер адреса в сегменте 16 бит — use16) или до 4 Гбайт данных (если размер адреса в сегменте 32 бит - use32).

Число пересылаемых элементов должно быть загружено в счетчик — регистр cx (use16) или ecx (use32).

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

В общем случае этот набор действий можно рассматривать как типовой для выполнения любой цепочечной команды:

  1.  Установить значение флага df в зависимости от того, в каком направлении будут обрабатываться элементы цепочки — в направлении возрастания или убывания адресов.
  2.  Загрузить указатели на адреса цепочек в памяти в пары регистров ds:(e)si и es: (e)di.
  3.  Загрузить в регистр ecx/cx количество элементов, подлежащих обработке.
  4.  Выдать команду movs с префиксом rep.

На примере листинга 1 рассмотрим, как эти действия реализуются программно. В этой программе производится пересылка символов из одной строки в другую. Строки находятся в одном сегменте памяти. Для пересылки используется команда-примитив movs с префиксом повторения rep.

 

Листинг 1 Пересылка строк командой movs

;prg_11_1.asm

MASM

MODEL   small

STACK   256

.data

source  db      'Тестируемая строка','$'

;строка-источник

dest    db      19 DUP (' ')    ;строка-приёмник

.code

        assume  ds:@data,es:@data

main:   ;точка входа в программу

        mov     ax,@data        ;загрузка сегментных регистров

        mov     ds,ax   ;настройка регистров DS и ES

        ;на адрес сегмента данных

        mov     es,ax

        cld     ;сброс флага DF — обработка строки от начала к концу

        lea     si,source       ;загрузка в si смещения строки-источника

        lea     di,dest ;загрузка в DS смещения строки-приёмника

        mov     cx,20   ;для префикса rep — счетчик повторений (длина строки)

rep     movs    dest,source     ;пересылка строки

        lea     dx,dest

        mov     ah,09h  ;вывод на экран строки-приёмника

        int     21h

exit:

        mov     ax,4c00h

        int     21h

end     main

Операция сравнения цепочек

Команды, реализующие эту операцию-примитив, производят сравнение элементов цепочки-источника с элементами цепочки-приемника. Здесь ситуация с набором команд и методами работы с ними аналогична операции-примитиву пересылки цепочек.

TASM предоставляет программисту четыре команды сравнения цепочек, работающие с разными размерами элементов цепочки:

cmps адрес_приемника,адрес_источника(CoMPare String) — сравнить строки;

cmpsb (CoMPare String Byte) — сравнить строку байт;

cmpsw (CoMPare String Word) — сравнить строку слов;

cmpsd (CoMPare String Double word) — сравнить строку двойных слов.

Команда cmps

Синтаксис команды cmps:

cmps адрес_приемника,адрес_источника 

Здесь:

  1.  адрес_источника определяет цепочку-источник в сегменте данных. Адрес цепочки должен быть заранее загружен в пару ds:esi/si;
  2.  адрес_приемника определяет цепочку-приемник. Цепочка должна находиться в дополнительном сегменте, и ее адрес должен быть заранее загружен в пару es:edi/di.

Алгоритм работы команды cmps заключается в последовательном выполнении вычитания (элемент цепочки-источника — элемент цепочки-получателя) над очередными элементами обеих цепочек.

Принцип выполнения вычитания командой cmps аналогичен команде сравнения cmp. Она, так же, как и cmp, производит вычитание элементов, не записывая при этом результата, и устанавливает флаги zf, sf и of.

После выполнения вычитания очередных элементов цепочек командой cmps, индексные регистры esi/si и edi/di автоматически изменяются в соответствии со значением флага df на значение, равное размеру элемента сравниваемых цепочек.

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

С командой cmps можно использовать префикс повторения repe/repz или repne/repnz:

  1.  repe или repz — если необходимо организовать сравнение до тех пор, пока не будет выполнено одно из двух условий:
  2.  достигнут конец цепочки (содержимое ecx/cx равно нулю);
  3.  в цепочках встретились разные элементы (флаг zf стал равен нулю);
  4.  repne или repnz — если нужно проводить сравнение до тех пор, пока:
  5.  не будет достигнут конец цепочки (содержимое ecx/cx равно нулю);
  6.  в цепочках встретились одинаковые элементы (флаг zf стал равен единице).

Таким образом, выбрав подходящий префикс, удобно использовать команду cmps для поиска одинаковых или различающихся элементов цепочек.

Выбор префикса определяется причиной, которая приводит к выходу из цикла. Таких причин может быть две для каждого из префиксов. Для определения конкретной причины наиболее подходящим является способ, использующий команду условного перехода jcxz. Ее работа заключается в анализе содержимого регистра ecx/cx, и если оно равно нулю, то управление передается на метку, указанную в качестве операнда jcxz. Так как в регистре ecx/cx содержится счетчик повторений для цепочечной команды, имеющей любой из префиксов повторения, то, анализируя ecx/cx, можно определить причину выхода из зацикливания цепочечной команды. Если значение в ecx/cx не равно нулю, то это означает, что выход произошел по причине совпадения либо несовпадения очередных элементов цепочек.

Существует возможность еще больше конкретизировать информацию о причине, приведшей к окончанию операции сравнения. Сделать это можно с помощью команд условной передачи управления (табл. 1 и 2).

Таблица 1. Сочетание команд условной передачи управления с результатами команды cmps (для чисел со знаком)

Причина прекращения операции сравнения

Команда условного перехода, реализующая переход по этой причине

операнд_источник > операнд_приемник

jg

операнд_источник = операнд_приемник

je

операнд_источник <> операнд_приемник

jne

операнд_источник < операнд_приемник

jl

операнд_источник <= операнд_приемник

jle

операнд_источник >= операнд_приемник

jge

Таблица 2. Сочетание команд условной передачи управления с результатами команды cmps (для чисел без знака)

Причина прекращения операции сравнения

Команда условного перехода, реализующая переход по этой причине

операнд_источник > операнд_приемник

ja

операнд_источник = операнд_приемник

je

операнд_источник <> операнд_приемник

jne

операнд_источник < операнд_приемник

jb

операнд_источник <= операнд_приемник

jbe

операнд_источник >= операнд_приемник

jae

Как определить местоположение очередных совпавших или не совпавших элементов в цепочках?

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

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

В качестве примера рассмотрим программу из листинга 2, которая сравнивает две строки, находящиеся в одном сегменте. Используется команда cmps. Префикс повторения - repe.

 

 Листинг 2. Сравнение двух строк командой cmps

<1> ;prg_11_2.asm

<2> MODEL       small

<3> STACK       256

<4> .data

<5> match       db      0ah,0dh,'Строки совпадают.','$'

<6> failed      db      0ah,0dh,'Строки не совпадают','$'

<7> string1     db      '0123456789',0ah,0dh,'$';исследуемые строки

<8> string2     db      '0123406789','$'

<9> .code

<10> ASSUME     ds:@data,es:@data       ;привязка DS и ES к сегменту данных

<11> main:

<12>    mov     ax,@data        ;загрузка сегментных регистров

<13>    mov     ds,ax

<14>    mov     es,ax   ;настройка ES на DS

<15> ;вывод на экран исходных строк string1 и string2

<16>    mov     ah,09h

<17>    lea     dx,string1

<18>    int     21h

<19>    lea     dx,string2

<20>    int     21h

<21> ;сброс флага DF — сравнение в направлении возрастания  адресов

<22>    cld

<23>    lea     si,string1      ;загрузка в si смещения string1

<24>    lea     di,string2      ;загрузка в di смещения string2

<25>    mov     cx,10   ;длина строки для префикса repe

<26> ;сравнение строк (пока сравниваемые элементы строк равны)

<27> ;выход при обнаружении не совпавшего элемента

<28> cycl:

<29>    repe    cmps    string1,string2

<30>    jcxz    equal   ;cx=0, то есть строки совпадают

<31>    jne     not_match       ;если не равны — переход на not_match

<32> equal:             ;иначе, если совпадают, то

<33>    mov     ah,09h  ;вывод сообщения

<34>    lea     dx,match

<35>    int     21h

<36>    jmp     exit    ;выход

<37> not_match:         ;не совпали

<38>    mov     ah,09h

<39>    lea     dx,failed

<40>    int     21h     ;вывод сообщения

<41> ;теперь, чтобы обработать не совпавший элемент в

 строке, необходимо уменьшить значения регистров si и di

<42>    dec     si

<43>    dec     di

<44> ;сейчас в ds:si и es:di адреса несовпавших элементов

<45> ;здесь вставить код по обработке несовпавшего элемента

<46> ;после этого продолжить поиск в строке:

<47>    inc     si

<48>    inc     di

<49>    jmp     cycl

<50> exit:      ;выход

<51>    mov     ax,4c00h

<52>    int     21h

<53> end        main    ;конец программы

Программа достаточно прозрачна, только два момента, на мой взгляд, требуют пояснения:

  1.  во-первых, строки 42 и 43, в которых мы скорректировали адреса очередных элементов для получения адресов несовпавших элементов. Вы должны понимать, что если сравниваются цепочки с элементами слов или двойных слов, то корректировать содержимое esi/si и edi/di нужно на 2 и 4 байта соответственно;
  2.  во-вторых, строки 47–49. Смысл их в том, что для просмотра оставшейся части строк необходимо установить указатели на следующие элементы строк за последними несовпавшими. После этого можно повторить весь процесс просмотра и обработки несовпавших элементов в оставшихся частях строк. 

Операция сканирования цепочек

Команды, реализующие эту операцию-примитив, производят поиск некоторого значения в области памяти. Логически эта область памяти рассматривается как последовательность (цепочка) элементов фиксированной длины размером 8, 16 или 32 бит.

Искомое значение предварительно должно быть помещено в регистр al/ax/eax. Выбор конкретного регистра из этих трех должен быть согласован с размером элементов цепочки, в которой осуществляется поиск.

Система команд микропроцессора предоставляет программисту четыре команды сканирования цепочки.

Выбор конкретной команды определяется размером элемента:

scas адрес_приемника (SCAning String) — сканировать цепочку;

scasb (SCAning String Byte) — сканировать цепочку байт;

scasw (SCAning String Word) — сканировать цепочку слов;

scasd (SCAning String Double Word) — сканировать цепочку двойных слов.

Команда scas

scas адрес_приемника 

Команда имеет один операнд, обозначающий местонахождение цепочки в дополнительном сегменте (адрес цепочки должен быть заранее сформирован в es:edi/di).

Транслятор анализирует тип идентификатора адрес_приемника, который обозначает цепочку в сегменте данных, и формирует одну из трех машинных команд scasb, scasw или scasd.

Условие поиска для каждой из этих трех команд находится в строго определенном месте. Так, если цепочка описана с помощью директивы db, то искомый элемент должен быть байтом и находиться в al, а сканирование цепочки осуществляется командой scasb; если цепочка описана с помощью директивы dw, то это — слово в ax, и поиск ведется командой scasw; если цепочка описана с помощью директивы dd, то это — двойное слово в eax, и поиск ведется командой scasd. Принцип поиска тот же, что и в команде сравнения cmps, то есть последовательное выполнение вычитания

(содержимое_регистра_аккумулятора - содержимое_очередного_элемента_цепочки).

В зависимости от результатов вычитания производится установка флагов, при этом сами операнды не изменяются.

Так же, как и в случае команды cmps, с командой scas удобно использовать префиксы repe/repz или repne/repnz:

  1.  repe или repz — если нужно организовать поиск до тех пор, пока не будет выполнено одно из двух условий:
    1.  достигнут конец цепочки (содержимое ecx/cx равно 0);
    2.  в цепочке встретился элемент, отличный от элемента в регистре al/ax/eax;
  2.  repne или repnz — если нужно организовать поиск до тех пор, пока не будет выполнено одно из двух условий:
    1.  достигнут конец цепочки (содержимое ecx/cx равно 0);
    2.  в цепочке встретился элемент, совпадающий с элементом в регистре al/ax/eax.

Таким образом, команда scas с префиксом repe/repz позволяет найти элемент цепочки, отличающийся по значению от заданного в аккумуляторе.

Команда scas с префиксом repne/repnz позволяет найти элемент цепочки, совпадающий по значению с элементом в аккумуляторе.

В качестве примера рассмотрим листинг 3, который производит поиск символа в строке.

В программе используется команда-примитив scas.

Символ задается явно (строка 20).

Префикс повторения — repne.

 

 Листинг 3. Поиск символа в строке командой scas

<1> ;prg_11_3.asm

<2> MASM

<3> MODEL       small

<4> STACK       256

<5> .data

<6> ;тексты сообщений

<7> fnd db      0ah,0dh,'Символ найден! ','$'

<8> nochar      db      0ah,0dh,'Символ не найден.','$'

<9> ;строка для поиска

<10> string     db      'Поиск символа в этой строке.',0ah,0dh,'$'

<11> .code

<12> ASSUME     ds:@data,es:@data

<13> main:

<14>    mov     ax,@data

<15>    mov     ds,ax

<16>    mov     es,ax   ;настройка ES на DS

<17>    mov     ah,09h

<18>    lea     dx,string

<19>    int     21h     ;вывод сообщения string

<20>    mov     al,'а'  ;символ для поиска — `а`(кириллица)

<21>    cld             ;сброс флага df

<22>    lea     di,string       ;загрузка в es:di смещения строки

<23>    mov     cx,29   ;для префикса repne — длина строки

<24> ;поиск в строке (пока искомый символ и символ в строке не совпадут)

<25> ;выход при первом совпадении

<26> repne      scas    string

<27>    je      found   ;если равны — переход на обработку,

<28> failed:    ;иначе выполняем некоторые действия

<29> ;вывод сообщения о том, что символ не найден

<30>    mov     ah,09h

<31>    lea     dx,nochar

<32>    int     21h     ;вывод сообщения nochar

<33>    jmp     exit    ;на выход

<34> found:             ;совпали

<35>    mov     ah,09h

<36>    lea     dx,fnd

<37>    int     21h ;вывод сообщения fnd

<38> ;теперь, чтобы узнать место, где совпал элемент в  строке,

<39> ;необходимо уменьшить значение в регистре di и  вставить нужный обработчик

<40> ;  dec     di

<41> ... вставьте обработчик

<42> exit:              ;выход

<43>    mov     ax,4c00h

<44>    int     21h

<45> end        main

Загрузка элемента цепочки в аккумулятор

Эта операция-примитив позволяет извлечь элемент цепочки и поместить его в регистр-аккумулятор al, ax или eax. Эту операцию удобно использовать вместе с поиском (сканированием) с тем, чтобы, найдя нужный элемент, извлечь его (например, для изменения).

Возможный размер извлекаемого элемента определяется применяемой командой.

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

lods адрес_источника (LOaD String) — загрузить элемент из цепочки в регистр-аккумулятор al/ax/eax;

lodsb (LOaD String Byte) — загрузить байт из цепочки в регистр al;

lodsw (LOaD String Word) — загрузить слово из цепочки в регистр ax;

lodsd (LOaD String Double Word) — загрузить двойное слово из цепочки в регистр eax.

Рассмотрим работу этих команд на примере lods.

Команда lods

lods адрес_источника (LOaD String) — загрузить элемент из цепочки в аккумулятор al/ax/eax.

Команда имеет один операнд, обозначающий строку в основном сегменте данных. Работа команды заключается в том, чтобы извлечь элемент из цепочки по адресу, соответствующему содержимому пары регистров ds:esi/si, и поместить его в регистр eax/ax/al. При этом содержимое esi/si подвергается инкременту или декременту (в зависимости от состояния флага df) на значение, равное размеру элемента.

Эту команду удобно использовать после команды scas, локализующей местоположение искомого элемента в цепочке.

Префикс повторения в этой команде может и не понадобиться — все зависит от логики программы.

В качестве примера рассмотрим листинг 4. Программа сравнивает командой cmps две цепочки байт в памяти string1 и string2 и помещает первый несовпавший байт из string2 в регистр al. Для загрузки этого байта в регистр-аккумулятор al используется команда lods. Префикса повторения в команде lods нет, так как он попросту не нужен.

 

Листинг 4. Использование lods для загрузки байта в регистр al

<1> ;prg_11_4.asm

<2> MASM

<3> MODEL       small

<4> STACK       256

<5> .data

<6> ;строки     для     сравнения

<7> string1     db      'Поиск символа в этой строке.',0ah,0dh,'$'

<8> string2     db      'Поиск символа не в этой строке.',0ah,0dh,'$'

<9> mes_eq      db      'Строки совпадают.',0ah,0dh,'$'

<10> fnddb      'Несовпавший элемент в регистре al',0ah,0dh,'$'

<11> .code

<12> ;привязка ds и es к сегменту данных

<13> assume     ds:@data,es:@data

<14> main:

<15>    mov     ax,@data        ;загрузка сегментных регистров

<16>    mov     ds,ax

<17>    mov     es,ax   ;настройка es на ds

<18>    mov     ah,09h

<19>    lea     dx,string1

<20>    int     21h     ;вывод string1

<21>    lea     dx,string2

<22>    int     21h     ;вывод string2

<23>    cld     ;сброс флага df

<24>    lea     di,string1      ;загрузка в es:di смещения

<25> ;строки string1

<26>    lea     si,string2      ;загрузка в ds:si смещения

<27> ;строки string2

<28>    mov     cx,29   ;для префикса repe — длина строки

<29> ;поиск в строке (пока нужный символ и символ в строке не равны)

<30> ;выход — при первом несовпавшем

<31> repe       cmps    string1,string2

<32>    jcxz    eql     ;если равны — переход на eql

<33>    jmp     no_eq   ;если не равны — переход на no_eq

<34> eql:               ;выводим сообщение о совпадении строк

<35>    mov     ah,09h

<36>    lea     dx,mes_eq

<37>    int     21h     ;вывод сообщения mes_eq

<38>    jmp     exit    ;на выход

<39> no_eq:     ;обработка несовпадения элементов

<40>    mov     ah,09h

<41>    lea     dx,fnd

<42>    int     21h     ;вывод сообщения fnd

<43> ;теперь, чтобы извлечь несовпавший элемент из строки

<44> ;в регистр-аккумулятор,

<45> ;уменьшаем значение регистра si и тем самым перемещаемся

<46> ;к действительной позиции элемента в строке

<47>    dec     si      ;команда lods использует ds:si-адресацию

<48> ;теперь ds:si указывает на позицию в string2

<49>    lods    string2 ;загрузим элемент из строки в AL

<50> ;нетрудно догадаться, что в нашем примере это символ — "н"

<51> exit:              ;выход

<52>    mov     ax,4c00h

<53>    int     21h

<54> end        main

 

Перенос элемента из аккумулятора в цепочку

Эта операция-примитив позволяет произвести действие, обратное команде lods, то есть сохранить значение из регистра-аккумулятора в элементе цепочки.

Эту операцию удобно использовать вместе с операцией поиска (сканирования) scans и загрузки lods, с тем, чтобы, найдя нужный элемент, извлечь его в регистр и записать на его место новое значение.

Команды, поддерживающие эту операцию-примитив, могут работать с элементами размером 8, 16 или 32 бит.

TASM предоставляет программисту четыре команды сохранения элемента цепочки из регистра-аккумулятора, работающие с элементами разного размера:

stos адрес_приемника (STOre String) — сохранить элемент из регистра-аккумулятора al/ax/eax в цепочке;

stosb (STOre String Byte) — сохранить байт из регистра al в цепочке;

stosw (STOre String Word) — сохранить слово из регистра ax в цепочке;

stosd (STOre String Double Word) - сохранить двойное слово из регистра eax в цепочке.

Команда stos

stos адрес_приемника (STOrage String) — сохранить элемент из регистра-аккумулятора al/ax/eax в цепочке.

Команда имеет один операнд адрес_приемника, адресующий цепочку в дополнительном сегменте данных.

Работа команды заключается в том, что она пересылает элемент из аккумулятора (регистра eax/ax/al) в элемент цепочки по адресу, соответствующему содержимому пары регистров es:edi/di. При этом содержимое edi/di подвергаются инкременту или декременту (в зависимости от состояния флага df) на значение, равное размеру элемента цепочки.

Префикс повторения в этой команде может и не понадобиться — все зависит от логики программы. Например, если использовать префикс повторения rep, то можно применить команду для инициализации области памяти некоторым фиксированным значением.

В качестве примера рассмотрим листинг 5. Программа производит замену в строке всех символов “а” на другой символ. Символ для замены вводится с клавиатуры.

 

Листинг 5. Замена командой stos символа в строке на вводимый с клавиатуры

;prg_11_5.asm

MASM

MODEL   small

STACK   256

.data

;сообщения

fnd     db      0ah,0dh,'Символ найден','$'

nochar  db 0ah,0dh,'Символ не найден.','$'

mes1    db      0ah,0dh,'Исходная строка:','$'

string  db      'Поиск символа в этой строке.',0ah,0dh,'$' ;строка для поиска

mes2    db      0ah,0dh,'Введите символ, на который следует заменить найденный'

        db      0ah,0dh,'$'

mes3    db      0ah,0dh,'Новая строка: ','$'

.code

 assume ds:@data,es:@data привязка ds и es к сегменту данных

main:           ;точка входа в программу

        mov     ax,@data        ;загрузка сегментных регистров

        mov     ds,ax

        mov     es,ax   ;настройка es на ds

        mov     ah,09h

        lea     dx,mes1

        int     21h     ;вывод сообщения mes1

        lea     dx,string

        int     21h     ;вывод string

        mov     al,'а'  ;символ для поиска-`а`(кириллица)

        cld             ;сброс флага df

        lea     di,string       ;загрузка в di смещения string

        mov     cx,29   ;для префикса repne — длина строки

;поиск в строке string до тех пор, пока

;символ в al и очередной символ в строке

;не равны: выход - при первом совпадении

cycl:

repne   scas string

        je      found   ;если элемент найден то переход на found

failed:         ;иначе, если не найден, то вывод сообщения nochar

        mov     ah,09h

        lea     dx,nochar

        int     21h

        jmp     exit    ;переход на выход

found:

        mov     ah,09h

        lea     dx,fnd

        int     21h ;вывод сообщения об обнаружении символа

;корректируем di для получения значения

;действительной позиции совпавшего элемента

;в строке и регистре al

        dec     di

new_char:       ;блок замены символа

        mov     ah,09h

        lea     dx,mes2

        int     21h     ;вывод сообщения mes2

;ввод символа с клавиатуры

        mov     ah,01h

        int     21h     ;в al — введённый символ

        stos    string  ;сохраним введённый символ

 ;(из al) в строке string в позиции старого символа

        mov     ah,09h

        lea     dx,mes3

        int     21h     ;вывод сообщения mes3

        lea     dx,string

        int     21h ;вывод сообщения string

;переход на поиск следующего символа ‘а’ в

строке

        inc     di              ;указатель в строке string на следующий,

 ;после совпавшего, символ

        jmp     cycl    ;на продолжение просмотра string

exit:           ;выход

        mov     ax,4c00h

        int     21h

end     main    ;конец программы

Следующие две команды появились впервые в системе команд микропроцессора i386. Они позволяют организовать эффективную передачу данных между портами ввода-вывода и цепочками в памяти. Следует отметить, что эти две команды позволяют достичь скорости передачи данных со скоростью выше той, которую может обеспечить контроллер DMA (Direct Memory Access — прямой доступ к памяти). Контроллер DMA — это специальная микросхема, предназначенная для того, чтобы освободить микропроцессор от управления процессом ввода-вывода больших массивов данных между внешним устройством (диском) и памятью. 

Ввод элемента цепочки из порта ввода-вывода

Данная операция позволяет произвести ввод цепочки элементов из порта ввода-вывода и реализуется командой ins, имеющей следующий формат:

ins адрес_приемника,номер_порта (Input String) - ввести элементы из порта ввода-вывода в цепочку.

Эта команда вводит элемент из порта, номер которого находится в регистре dx, в элемент цепочки, адрес которого определяется операндом адрес_приемника.

Несмотря на то, что цепочка, в которую вводится элемент, адресуется указанием этого операнда, ее адрес должен быть явно сформирован в паре регистров es:edi/di.

Размер элементов цепочки должен быть согласован с размерностью порта — он определяется директивой резервирования памяти, с помощью которой выделяется память для размещения элементов цепочки.

После пересылки команда ins производит коррекцию содержимого edi/di на величину, равную размеру элемента, участвовавшего в операции пересылки. Как обычно, при работе цепочечных команд учитывается состояние флага df.

Подобно командам, реализующим рассмотренные выше цепочечные операции-примитивы, транслятор преобразует команду ins в одну из трех машинных команд без операндов, работающих с цепочками элементов определенного размера:

insb (INput String Byte) — ввести из порта цепочку байт;

insw (INput String Word) — ввести из порта цепочку слов;

insd (INput String Double Word) — ввести из порта цепочку двойных слов.

К примеру, выведем 10 байт из области памяти pole в порт 5000h.

 

.data

pole    db      10 dup (‘ ‘)

.code

...

        push    ds

        pop     es      ;настройка es на ds

        mov     dx,5000h

        lea     di,pole

        mov     cx,10

rep     insb

...

Вывод элемента цепочки в порт ввода-вывода

Данная операция позволяет произвести вывод элементов цепочки в порт ввода-вывода. Она реализуется командой outs, имеющей следующий формат:

outs номер_порта,адрес_источника (Output String) — вывести элементы из цепочки в порт ввода-вывода.

Эта команда выводит элемент цепочки в порт, номер которого находится в регистре dx. Адрес элемента цепочки определяется операндом адрес_источника. Несмотря на то, что цепочка, из которой выводится элемент, адресуется указанием этого операнда, значение адреса должно быть явно сформировано в паре регистров ds:esi/si.

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

После пересылки команда outs производит коррекцию содержимого esi/si на величину, равную размеру элемента цепочки, участвовавшего в операции пересылки. При этом, как обычно, учитывается состояние флага df.

Подобно команде ins, транслятор преобразует команду outs в одну из трех машинных команд без операндов, работающих с цепочками элементов определенного размера:

outsb (OUTput String Byte) — вывести цепочку байт в порт ввода-вывода;

outsw (OUTtput String Word) — вывести цепочку слов в порт ввода-вывода;

outsd (OUTput String Double Word) — вывести цепочку двойных слов в порт ввода- вывода.

В качестве примера рассмотрим фрагмент программы, которая выводит последовательность символов в порт ввода-вывода, соответствующего принтеру (номер 378 (lpt1)).

 

.data

str_pech        db      'Текст для печати'

.code

...

        mov     dx,378h

        lea     di,str_pech

        mov     cx,16

rep     outsb

...

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


 

А также другие работы, которые могут Вас заинтересовать

25226. Субстанціальстська інтерпретація природи людини 21.5 KB
  Спіноза – визначав протяжність і мислення атрибутами єдиної С. найважливішою логік категорією апріорною формою мислення яка здійснює синтез явищ даних у досвіді. як істотний ступінь у розвитку ідеї основа всякого справжнього розвитку начало наук мислення що повинне виявляти диференціацію єдиного у багатоманітне.
25227. Поняття волі у філософії Шопенгауера та Нацше 23 KB
  Воля є центром мотивації свідомості внутрішньою сутністю людини. Саме воля спонукає нас до дії і весь світ у рух. Воля не має основи не підкоряється закону достатньої підстави а існує сама собою і для себе. Воля проявляється як об’єктивна як природа включаючи і людське тіло так і суб’єктивно – як свідома воля.
25228. Шеллінг “Філософія мистецтва”: поняття мистецтва 34.5 KB
  Шеллінг €œФілософія мистецтва€: поняття мистецтва €œФілософія мистецтва€ уособлює цілий етап в розвитку естетичної думку від Канта до Гегеля Основний вплив: Кант Шиллєр Фіхте. він конструює ідеальну модель світу мистецтва. Шеллінг намагається визначити місце мистецтва в універсумі і тим самим з’ясувати його внутрішню необхідність і метафізичний смисл. Краса проявляється там де особливе реальне в такій мірі відповідає своєму поняттю що воно поняття як нескінчене вступає в кінцеве в усій своїй особливості так що реальне...
25229. Критерії вибору теорії (Поппер, Кун, Фейрабенд) 33 KB
  Поппер видiляє декiлька видiв змiсту теорiй. Перш за все згiдно критерiя демаркацiї усяка наукова теорiя має емпiричний змiст сукупнiсть тих базисних речень котрi вона забороняє. Iнакше кажучи емпiричний змiст теорiї дорiвнює класовi її потенцiйних фальсифiкаторiв. Логiчним змiстом деякого твердження чи теорiї Т символiчно CtT Поппер називає клас всiх логiчних наслiдкiв Т.
25230. Суть Сократових тез “Пізнай самого себе” і ”Я знаю лише те, що Я нічого не знаю” 25 KB
  Характерним для класики стає пізнання чуттєвого космосу в якості об’єкту. Відкриває метод отримання істинного знання шляхом відкриття у загальному сутнісного змісту одиничного що дозволяє керуватись у пошуках істини добра і краси. На відміну від софістів які вважали себе справжніми вчителями мудрості Сократ критично ставився до власного знання: €œя знаю тільки що я нічого не знаю€ – методологічний сумнів головний зміст якого полягає в тому що отримати знання людина може лише власними духовнодушевними зусиллями не очікуючи його...
25231. Платон про ідеї як „досконалі речі” 28 KB
  Платон про ідеї як досконалі речі€ Оригінальне вчення про ідеї. Ідеї вічні незмінні безвідносні вони не залежать від умов простору і часу. По відношенню до чуттєвих речей ідеї одночасно є їх причинами і тими зразками за якими були створені ці речи. Водночас ідеї є метою до якої прагнуть істоти чуттєвого світу.
25232. Еллінізм: відкриття духовної реальності (Сенека, Епіктет) 29.5 KB
  Саме тут вперше на основі причасності всіх людей логосу формується ідея спільного братства на місце ідеалу національної держави приходить космополітизм. Нехай з середини ти будеш інший у всьому а ззовні ми не повинні відрізнятись від людей.€ Перше що обіцяє дати філософія – це вміння жити серед людей. Епіктет проповідував близькі до християнства ідеї про різку відмінність Духа від тіла про братську любов до всіх людей про необхідність постійного звернення людини до бога.
25233. Епікуреїзм: таємниця «паренклізісу» (самочинне відхилення атомів від лінії необхідності) 22.5 KB
  грекоримський епікуреїзм – середній Сад епікуреїзм у Римі – пізній Сад.
25234. К. Леві-Строс Структурна антропологія 33.5 KB
  полягає в застосуванні структурного методу до аналізу історикоетнографічних процесів культури – як окремого людського буття так і етногенезу в цілому а також до становлення окремих форм соціального буття. полягає в тому щоб в процесі аналізу конкретної етнографічної проблематики наблизитися до осягнення проблеми становлення і формування людського суспільства і людської культури. З огляду на це вивчення життя первісних народів є ключем для розуміння загальних закономірностей культури. Енґельса оскільки момент якісного стрибка від...