m: shl bx,4
movah,01h
int 21h вводим n в регистр bx
sub ax,130h
add bx,ax
loop m
mov cx,bxxor dx,dx
xoral,al
m1: adddx,cx считаем у
jnc m2
mov al,1
m2: loop m1
cmp al,1
je m3
mov ym,dx
m3: mov yb,edx
mov ax,4c00h
int 21h
Цепочка – это последовательность элементов, размер которых может быть байт, слово, двойное слово. Содержимое этих элементов может быть любое – символы, числа. В системе команд микропроцессора имеется семь операций-примитивов обработки цепочек. Каждая из них реализуется в микропроцессоре тремя командами, в свою очередь, каждая из этих команд работает с соответствующим размером элемента — байтом, словом или двойным словом.
Типовой набор действий для выполнения любой цепочечной команды:
- Установить значение флага df в зависимости от того, в каком направлении будут обрабатываться элементы цепочки — в направлении возрастания или убывания адресов.
- Загрузить указатели на адреса цепочек в памяти в пары регистров ds:(e)si и es: (e)di.
- Загрузить в регистр ecx/cx количество элементов, подлежащих обработке.
- Выдать цепочечную команду с префиксом повторений.
Пересылка цепочек
movs адрес_прием, адрес_источника (MOVeString)- переслать цепочку;
movsbMOVe String Byte) — переслатьцепочкубайт;
movsw (MOVe String Word) — переслатьцепочкуслов;
movsd (MOVe String Double word) — переслатьцепочкудвойныхслов.
Команда копирует байт, слово или двойное слово из цепочки источника, в цепочку приемника. Размер пересылаемых элементов ассемблер определяет, исходя из атрибутов идентификаторов. К примеру, если эти идентификаторы были определены директивой db, то пересылаться будут байты, если идентификаторы были определены с помощью директивы dd, то пересылке подлежат двойные слова.
Для цепочечных команд с операндами типа movs адрес_приемника,адрес_источника, не существует машинного аналога. При трансляции в зависимости от типа операндов транслятор преобразует ее в одну из трех машинных команд: movsb, movsw или movsd.
Сама по себе команда movs пересылает только один элемент, исходя из его типа, и модифицирует значения регистров esi/si и edi/di. Если перед командой написать префикс rep, то одной командой можно переслать до 64 Кбайт данных. Число пересылаемых элементов должно быть загружено в счетчик — регистр cx (use16) или ecx (use32).
Пример 13. Пересылка строк командой movs
MODELsmall
.STACK256
.datasource db 'Тестируемая строка','$' ;строка-источник
dest db 19 DUP (' ') ;строка-приёмник
.code
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
mov ax,4c00h
int 21h
endmainОперация сравнения цепочек
cmps адрес_приемника,адрес_источника(CoMPare String) — сравнить строки;
cmpsb (CoMPare String Byte) — сравнитьстрокубайт;
cmpsw (CoMPare String Word) — сравнитьстрокуслов;
cmpsd (CoMPare String Double word) — сравнитьстрокудвойныхслов.
Алгоритм работы команды cmps заключается в последовательном выполнении вычитания (элемент цепочки-источника — элемент цепочки-получателя) над очередными элементами обеих цепочек. Принцип выполнения вычитания командой cmps аналогичен команде сравнения cmp. Она, так же, как и cmp, производит вычитание элементов, не записывая при этом результата, и устанавливает флаги zf, sf и of.
После выполнения вычитания очередных элементов цепочек командой cmps, индексные регистры esi/si и edi/di автоматически изменяются в соответствии со значением флага df на значение, равное размеру элемента сравниваемых цепочек.
Операция сканирования цепочек
scas адрес_приемника (SCAning String) — сканировать цепочку;
scasb (SCAningStringByte) — сканировать цепочку байт;
scasw (SCAning String Word) — сканироватьцепочкуслов;
scasd (SCAning String Double Word) — сканироватьцепочкудвойныхслов
Эти команды осуществляют поиск искомого значения, которое находится в регистре al/ax/eax. Принцип поиска тот же, что и в команде сравнения cmps, то есть последовательное выполнение вычитания
(содержимое регистра_аккумулятора – содержимое очередного_элемента_цепочки).
В зависимости от результатов вычитания производится установка флагов, при этом сами операнды не изменяются.
Загрузка элемента цепочки в аккумулятор
lods адрес_источника(LOaD String) — загрузить элемент из цепочки в регистр-аккумулятор al/ax/eax;
lodsb(LOaD String Byte) — загрузить байт из цепочки в регистр al;
lodsw (LOaDStringWord) — загрузить слово из цепочки в регистр ax;
lodsd (LOaDStringDoubleWord) — загрузить двойное слово из цепочки в регистр eax.
Эта операция-примитив позволяет извлечь элемент цепочки и поместить его в регистр-аккумулятор al, ax или eax. Эту операцию удобно использовать вместе с поиском (сканированием) с тем, чтобы, найдя нужный элемент, извлечь его (например, для изменения).
Перенос элемента из аккумулятора в цепочку
stos адрес_приемника(STOre String) - сохранить элемент из регистра-аккумулятора al/ax/eax в цепочке;
stosb (STOreStringByte) - сохранить байт из регистра al в цепочке;
stosw(STOreStringWord) - сохранить слово из регистра ax в цепочке;
stosd (STOreStringDoubleWord) - сохранить двойное слово из регистра eax в цепочке.
Эта операция-примитив позволяет произвести действие, обратное команде lods, то есть сохранить значение из регистра-аккумулятора в элементе цепочки. Эту операцию удобно использовать вместе с операцией поиска (сканирования) scans и загрузки lods, с тем, чтобы, найдя нужный элемент, извлечь его в регистр и записать на его место новое значение.
Пример 14. Подсчитайте количество несовпадающих элементов в заданной и введенной строках.
Model small
.stack 100h
.data
s0 db ‘Заданнаястрока$’
s1 db16 ;задаем количество символов во вводимой строке + знак Enters
s2 db?, 16 dup (?) ; ?- под количество введенных символов, массив под строку
s3 db 10,13, ‘Количество несовпадающих элементов - $' ;информац. строка
.code
movax, @data
movds, ax ;задаем адрес сегмента данных
moves, ax ;настраиваем адрес сегмента данных, где хранится строка приемник
;вводим сравниваемую строку
movah, 0ah
mov dx, offset s1
int 21h
;выводим информационную строку
movah, 09h
mov dx, offset s3
int 21h
;сравниваем строки, один элемент из заданной строки сравниваем со всеми ; элементами введенной строки
movdl,’0’ ;в dlascii-код 0
movcx, 16 ;в сх количество элементов в заданной строке
movsi, offsets0 ;в si адрес заданной строки-источника
z_str: pushcx ;сохраняем счетчик внешних циклов в стеке
lodsb ;загружаем элемент из заданной строки в аккумулятор, al
movdi, offsets2 ;в di адрес введенной строки-приемника
movcl, s2[di] ;в cl количество введенных элементов
xorch, ch ; обнуляем ch, т.к. в цикле счетчиком является сх
incdi ;на первый элемент строки-приемника
repescacb
;сканируем строку-приемник до тех пор пока элемент не = содержимому al,
;или пока не кончится строка
jzm1 ;zf=1, если в строке встретился элемент = содержимому al
incdl ; считаем количество не совпадающих элементов
m1: ;внутренний цикл по введенной строке закончился
popcx ;восстанавливаем содержимое сх
loopz_str
;после выхода из цикла в dl количество не совпадающих элементов
mov ah, 02h
int 21h ;выводим dl
mov ax,4c00h
int 21h
end
Массивы
Организация одномерных массивов
Все элементы массива располагаются в памяти последовательно
Описание элементов массива
masdb 1,2,3,4,5
masdw 5 dup (0)
movax,mas[si] ; в si номер элемента в массиве
movmas[si], ax ; в di номер элемента в массиве
Пример 15. Найти в строке хотя бы один нулевой элемент
modelsmall
.stack 100h
.data
buferdw 25 ;формирую размер буфера для ввода строки
masdb 25 dup (' ') ;формирую буфер
subj1 db ‘в строке найден нулевой элемент', '$'
subj2 db ‘в строке не найден нулевой элемент', '$'
.code
main:
mov ax,@data
movds,ax
; ввод строки с клавиатуры
mov ah,0ah
mov dx, offset bufer
int 21h
;поиск нулевого элемента
xorsi, si
movcl, mas[si] ;загружаем в сх количество элементов в строке
moval, 030h ;в ax загружаем ASCII код нуля
m1: inc si
cmp al, mas[si]
je m2
;если в строке найдем нулевой элемент, то выходим из цикла на вывод subj1
loopm1
;нормальный выход из цикла означает что в строке нет нулевых элементов
lea dx, subj2
jmp m3
m2: lea dx,subj1
m3: mov ah, 09h
int 21h
mov ax,4c00h
int 21h
end main
Организация двумерных массивов
!Специальных средств для описания двумерных массивов в ассемблере нет!
Двумерный массив описывается также как и одномерный массив, отличие заключается в трактовке расположения элементов. Пусть последовательность элементов трактуется как двумерный массив, расположенный по строкам, тогда адрес элемента [i,j] вычисляется так
База+колич_элем_строке*размер_элем*I+j
Пример 16. Найти максимальный элементы в каждой строке массива 5*7
model small
.stack 100h
.data
mas dw 5 dup( 7 dup(0))
max dw 0
subj db ‘введитестроку',13,10,'$'
.code
main:
mov ax, @data
mov ds, ax
;заполнение массива
xor si, si
mov cx, 05h
incykl: push cx
mov ah, 09h
lea dx, subj
int 21h ;вывод информационной строки
movcx, 07h
mov ah, 01h
outcykl: int 21h ;ввод элементов массива
movmas[si], ax ;размещение элементов на месте
inc si
inc si
loop outcykl
popcx
loopincykl
;поиск максимального/ минимального в строках
xor si,si
mov cx, 05h
s1t: push cx
mov cx, 06h
mov dx, mas[si]
maxi: add si, 2
cmpdx, mas[si]
ja min1 ;если меньше то переходим