Смекни!
smekni.com

Программная модель процессоров семейства X86 (стр. 6 из 9)

.code

main:

mov ax,@data

mov ds,ax

moves,ax;настройка ESна DS

;вводимстроку

mov ah,0ah

mov dx, offset s1

int 21h

;поиск *

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

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

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

incdi ;первый элемент в s3 это количество введенных символов, его игнорируем

xorbl ;обнуляем счетчик звездочек

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

m1: repne scasb ;пока искомый символ и символ в строке не совпадут идет поиск, ;выход при совпадении

je found ;если равны - переход на обработку

;вывод количества звездочек в строке

movah,09h

mov dx,offset s3

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

mov al,bl

aam

or ax, 3030h

mov dx,ax

xchg dh,dl

mov ah, 02h

int 21h

xchg dh,dl

int 21h

mov ax,4c00h

int 21h

;суммируем количество звездочек

found: incbl

jmpm1

endmain

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

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

lodsb(LOaDStringByte) — загрузить байт из цепочки в регистр 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, с тем, чтобы, найдя нужный элемент, извлечь его в регистр и записать на его место новое значение.

Сложные структуры данных

Одномерные массивы

Все элементы массива располагаются в памяти последовательно

Описание элементов массива

masdb 1,2,3,4,5

masdw 5 dup (0)

Доступ к элементам массива

movax,mas[si] ; в si номер элемента в массиве

movmas[si], ax ; в di номер элемента в массиве

Используя команды i486 можно использовать адресацию с масштабированием, при размере элементов больше байта

Movax, mas[si*2] ;

Пример программы Найти в строке хотя бы один нулевой элемент

modelsmall

.stack 100h

.data

buferdw 25 ;формирую размер буфера для ввода строки

masdw 25 dup (' ') ;формирую буфер

adrdwbufer ;описываю адрес

subj1 db ‘в строке найден нулевой элемент', '$'

subj2 db ‘в строке не найден нулевой элемент', '$'

.code

main:

mov ax,@data

movds,ax

mov ah,0ah

mov dx, adr

int 21h ; ввод строки с клавиатуры

;поиск нулевого элемента

xorsi, si

movcx, mas[si] ;загружаем в сх количество элементов в строке

movax, 030h ;в ax загружаем ASCII код нуля

m1: inc si либоinc si

inc si cmp ax, mas[si*2]

cmpax, mas[si]

jem2 ;если в строке найдем нулевой элемент, то выходим из цикла на вывод subj1

loopm1

;нормальный выход из цикла означает что в строке нет нулевых элементов

mov ah,09h

lea dx, subj2

int 21h

jmp exit

m2: mov ah, 09h

lea dx,subj1

int 21h

exit: mov ax,4c00h

int 21h

endmain

Двумерные массивов

!Специальных средств для описания двумерных массивов в ассемблере нет!

Двумерный массив описывается также как и одномерный массив, отличие заключается в трактовке расположения элементов. Пусть последовательность элементов трактуется как двумерный массив, расположенный по строкам, тогда адрес элемента [i,j] вычисляется так

База+колич_элем_строке*размер_элем*I+j

Для определения базы используют имя массива, для второго слагаемого регистр bx , для третьего si, это базово-индексная адресация.

Описание массива:

Mas1 db 10 dup (3 dup (?))

Mas2 db 1,2,3,4,5

3,4,5,6,7

4,7,9,2,0

Пример поиска максимального элемента в каждой строке однобайтного массива mas, размером 5*10, с занесением максимальных элементов в массив max (1*5). Инициализацию массива masрассматривать не будем.

xordi, di ;обнуляем индексы массива max

xorbx, bx ;обнуляем индексы строк массива mas

xorsi, si ;обнуляем индексы столбцов массива mas

movcx,5 ;в cx количество строк, внешний цикл

m1: pushcx

movcx, 10 ;в сх количество столбцов, внутренний цикл

moval, mas[si+bx];первый элемент из 1 строки mas в аl

m2: incsi

cmpal, mas[si+bx] ;сравниваем со следующим элем. строки

jbm3 ;если меньше на m3

moval, mas[si+bx] ;иначе в аl заносим больший элемент

m3: loopm2 ;после выхода из цикла в ах максимальный элемент в данной строке

movmax[di],al ;кладем максимальный элемент в массив max

incdi

xorsi,si ;обнуляем номер столбца

addbx, 10 ;переходим на следующую строку

popcx ;достаем сх

loopm1

Структура – это тип данных, состоящий из фиксированного числа элементов разного типа.

Для использования структур в программе необходимо выполнить три действия:

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

Синтаксис описания шаблона структуры:

имя_структуры STRUC

<описание полей> ; последовательность директив описания данных dd,dw,db…

имя_структуры ENDS

2. Определить экземпляр структуры. Этот этап подразумевает инициализацию конкретной переменной заранее определенной (с помощью шаблона) структурой. В данном случае транслятору дается указание выделить память и присвоить этой области символическое имя.

Описать структуру в программе можно только один раз, а определить – любое количество раз.

Определение данных с типом структуры имеет следующий вид:

[имя переменной] имя_структуры <[список значений]>

3. Организовать обращение к элементам структуры.

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

имя_переменной.имя_поля_структуры,

Фрагмент программы. Найти из списка студентов отличника по всем предметам.

Model small

.586p

Stud struc

Name db 20 dup (‘’)

Phisika db ?

Matem db ?

Stud ends

.data

BuferStud <””,’’,’’,’’> ;зарезервировали пустую структуру

S1 Stud <”Ivanov”,’5’,’5’,’5’>

S2 Stud <”Petrov”,’3’,’3’,’3’>

S3 Stud <”Сидоров”,’5’,’2’,’5’>

mov bx, offset s1

mov al, [bx].Phisika

cmp al, ‘5’

jne m2

mov al, [bx].Matem

cmpal, ‘5’

jnem2

;нашли одного из отличников, надо вывести его фамилию

m2: moval, s2.Phisika;ищем следующего отличника

mov ah, s2.Matem

cmp ax, ‘55’

jnem3

;нашли одного из отличников, надо вывести его фамилию

m3: ;ищем следующего отличника

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

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

имя_объединения UNION

<описание полей>

имя_объединения ENDS

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

Model small

.586p

st union

stu1 dw ?

stu2 db ?

stu3 dd ?

st ends

.data

qst <> ;пустое объединение

zst <12ffh> ;заполнили объединение значением

movq.stu2, al ;в переменную положили содержимое регистра al

mov q.stu3, edx

mov bx, z.stu1

movdx, offsetq.stu1

Запись - структурный тип данных, состоящий из фиксированного числа элементов длиной от одного до нескольких бит. При описании записи для каждого элемента указывается его длина в битах и, что необязательно, некоторое значение. Суммарный размер записи определяется суммой размеров ее полей и не может быть более 8, 16 или 32 бит. Если суммарный размер записи меньше указанных значений, то все поля записи “прижимаются” к младшим разрядам

Использование записей в программе, так же, как и структур, организуется в три этапа:

1. Описание шаблона записи

имя_записи RECORD <описание элементов>

2. Для использования шаблона записи в программе необходимо определить переменную с типом данной записи, для чего применяется следующая синтаксическая конструкция (рис. 7):

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

- каждому имени элемента записи ассемблер присваивает числовое значение, равное количеству сдвигов вправо, которое нужно произвести, для того чтобы этот элемент оказался прижатым к началу ячейки памяти;

- размер элемента записи в битах можно узнать с помощью оператора width;

- оператор mask позволяет локализовать биты нужного элемента записи;

- все действия по преобразованию элементов записи производятся с помощью логических команд;

- команда setfield устанавливает значение некоторого поля записи

setfield имя_элемента_записи регистр_ назначение, регистр_источник

- команда getfield осуществляет выборку некоторого поля записи

getfield имя_элемента_записи регистр_назначение, регистр_ источник

Процедуры. Макрокоманды

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