Пример использования команд усл. перехода, сравнения и циклов

Дана матрица целых байтовых величин, размером 4*5, необходимо подсчитать количество нулей и заменить их числом 0FFh. Под стек отведем 256 байтов, программу оформим как две последовательные процедуры: внешняя (FAR)– это связь с ОС, внутренняя (NEAR) – решение поставленной задачи.

1. ; prim.asm

2. title prim.asm

3. page , 132

4. Sseg segment para stack ‘stack’

5. db 256 dup (?)

6. Sseg ends

7. Dseg segment para public ‘data’

8. Dan db 0,2,5,0,91 ; адрес первого элемента массива

9. db 4,0,0,15,47 ; имя - Dan

10. db 24,15,0,9,55

11. db 1,7,12,0,4

12. Dseg ends

15. Cseg segment para public ‘code’

16. Assume cs: cseg, ds:dseg, ss:sseg

17. start proc far

18. push DS ; для связи

19. push AX ; с ОС

20. mov BX, Dseg ; загрузка адреса сегмента данных

21. mov DS, BX ; в регистр DS

22. call main

23. ret

24. start endp

25. main proc near

26. mov BX, offset Dan

27. mov CX, 4 ; количество повторений внешнего цикла

28. nz1: push CX

29. mov DL, 0 ; счетчик нулей в строке матрицы

30. mov SI, 0

31. mov CX, 5 ; количество повторений внутреннего цикла

32. nz2: push CX

33. cmp byte ptr [BX+SI], 0

34. jne mz

35. mov byte ptr [BX+SI], 0FFh

36. inc DL

37. mz: inc SI

38. pop CX

39. kz2: loop nz2

40. add DL, ‘0’ ; вывод на экран

41. mov AH, 6 ; количества нулей

42. int 21h

43. add BX, 5 ; переход к следующей строке матрицы

44. pop CX

45. kz1: loop nz1

46. ret

47. main endp

48. Sseg ends

49. end start

Задача решена с помощью двух вложенных циклов, во внутреннем осуществляется просмотр элементов текущей строки (32-39), увеличение счетчика нулей и пересылка константы 0FFh в байт, содержащий ноль. Во внешнем цикле осуществляется переход к следующей строке очисткой регистра SI (строка 30 ) и увеличением регистра BX на количество элементов в строке (40).

Физически последняя команда программы (49) в качестве параметра указывает метку команды, с которой необходимо начинать выполнение программы.

Директива title задает заголовок каждой странице листинга, заголовок может содержать до 60 символов.

Директива page устанавливает количество строк на странице листинга – 1-й параметр (здесь он отсутствует, значит берется значение по умолчанию 57) и количество символов в каждой строке ( здесь 132, возможно от 60 до 132, по умолчанию – 80).

Pageбезпараметров осуществляет перевод печати на новую страницу и увеличение на 1 номера страницы листинга.

Эти директивы могут отсутствовать.

30) Работа с массивами в Ассемблере, примеры.

Массивы в языке Ассемблер описываются директивами определения данных, возможно с использование конструкции повторения DUP.

Например, x DW 30 dup ( ? )

Так можно описать массив x, состоящий из 30 элементов длиной в слово, но в этом описании не указано как нумеруются элементы массива, т.е. это может быть x[0..29] и x[1..30] и x[k..29+k].

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

адрес (x[i]) = x + (type x) * i

В общем виде, когда первый элемент имеет номер k , для одномерного массива будет:

адрес (x[i]) = x + (type x) * (i – k)

Для двумерного массива - A[0..n-1, 0..m-1]адрес (i,j) – го элемента можно вычислить так:

адрес (A[i,j]) = A + m * (type A) * i + (type A) *j

С учетом этих формул для записи адреса элемента массива можно использовать различные способы адресации.

Для описанного выше массива слов, адрес его i-го элемента равен:

x + 2*i = x + type (x) * i,

Т.е. адрес состоит из двух частей: постоянной x и переменной 2 * i, зависящей от номера элемента массива. Логично использовать адресацию прямую с индексированием: x – смещение адреса относительно начала, а 2*i – в регистре модификаторе SI или DI x[ i ]

Для двумерного массива, например:

A DD n DUP (m Dup (?) ) ; A[0..n - 1, 0..m - 1] получим

адрес (A[ i,j ]) = A + m * 4 * i + 4 *j,

Т.е. имеем в адресе постоянную часть А и две переменных m * 4 * iи 4 *j ,которые можно хранить в регистрах. Два модификатора есть в адресации по базе с индексированием, например: A[BX][DI].

Фрагмент программы, в которой в регистр AL записывается количество строк матрицы X DB 10 dup ( 20 dup (?) ), в которых начальный элемент повторяется хотя бы один раз.

----------------------------------

mov AL, 0 ; количество искомых строк

mov CX, 10 ; количество повторений внешнего цикла

mov BX, 0 ; начало строки 20*i

m1: push CX

mov AH, X[BX] ; 1-й элемент строки в AH

mov CX, 19 ; количество повторений внутреннего цикла

mov DI, 0 ; номер элемента в строке ( j )

m2: inc DI ; j = j + 1

cmp AH, X[BX][DI] ; A[i,0] = A[i,j]

loopne m2 ; первый не повторился? Переход на m2

jne L ; не было в строке равных первому? Переход на L

inc AL ; первый повторился, увеличиваем счетчик строк

L: pop CX ; восстанавливаем CX для внешнего цикла

add BX, 20 ; в BX начало следующей строки

loop m1

------------------------------

12) Команды побитовой обработки данных: логические операции, операции сдвига.

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

Логические команды: and, or, xor, not. Для всех логических команд, кроме not, операнды одновременно не могут находиться в памяти, OF = CF = 0, AF – не определен, SF, ZF, PF определяются результатом команды.

and OP1, OP2; (OP1) логически умножается на (OP2), результат OP1

Пример: (AL) = 1011 0011, (DL) = 0000 1111,

and AL, DL; (AL) = 0000 0011

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

Например:

1) and CX, 0FFh ; маской является константа

2) and AX, CX ; маска содержится в регистре

3) and AX, TOT ; маска в ОП по адресу (DS) + TOT

4) and CX, TOT[BX+SI] ; …в ОП по адресу (DS) + (BX) + (SI) + TOT

5) and TOT[BX+SI], CX ; в ноль устанавливаются некоторые разряды ОП

6) and CL, 0Fh ; в ноль устанавливаются старшие 4 разряда регистра CL

Команда – or OP1, OP2; результатом является логическое сложение 1-ого со 2-ым и результат по адресу первого.0 – если оба нули.

Эта команда используется для установки в 1 заданных битов 1-го операнда с помощью маски OP2. … Например:

(AL) = 1011 0011, (DL) = 0000 1111

or AL, DL; (AL) = 1011 1111 ……

В команде могут использоваться различные операнды:

or CX, 00FFh ; or TAM, AL ; or TAM[BX][DX], CX

Если во всех битах результата будет 0, то ZF = 1.

Команда xor OP1, OP2; 1 xor 1 = 0, 0 xor 0 = 0, в ост. сл. = 1

Например: (AL) = 1011 0011, маска = 000 01111

xor AL, 0Fh; (AL) = 1011 1100

Команда not OP; результат – инверсия значения операнда

Если (AL) = 0000 0000, not AL; (AL) = 1111 1111

Значения флагов не изменяются.

Примеры.

1) xor AX, AX ; обнуляет регистр AX быстрее, чем mov и sub

2) xor AX, BX; меняет местами значения AX и BX

xor BX, AX ; быстрее, чем команда

xor AX, BX; xchg AX, BX

3) Определить количество задолжников в группе из 20 студентов. Информация о студентах содержится в массиве байтов X DB 20 DUP (?), причем в младших 4 битах каждого байта содержатся оценки, т.е. 1 – сдал экзамен, 0 – «хвост». В DL сохраним количество задолжников.

-----------------------------

mov DL, 0

mov SI, 0 ; i = 0

mov CX, 20 ; количество повторений цикла

nz: mov AL, X[SI]

and AL, 0Fh ; обнуляем старшую часть байта

xor AL, 0Fh ;

jz m ; ZF = 1, хвостов нет, передаем на повторение цикла

inc DL ; увеличиваем количество задолжников

m: inc SI ;переходим к следующему студенту

loop nz

add DL, “0”

mov AH, 6

int 21h

--------------------------

Команды сдвига.

Формат команд арифметического и логического сдвига можно представить так:

sXY OP1, OP2 ; <комментарий>

Здесь X - h или a, Y – l или r; OP1 – r (регистр) или m (память), OP2 – d (непоср) или CL. ХУ определяет тип и направление.

И для всех команд сдвига в CL используются только 5 младших разрядов, принимающих значения от 0 до 31. При сдвиге на один разряд:

Здесь знаковый бит распространяется на сдвигаемые разряды. Например, (AL) = 1101 0101

sar AL, 1 ; (AL) = 1110 1010 и CF = 1

Сдвиги больше, чем на 1,эквивалентны соответствующим сдвигам на 1, выполненным последовательно.

Сдвиги повышенной точности для i186 и выше:

shrd OP1, OP2, OP3 ;

shld OP1, OP2, OP3 ;

Содержимое первого операнда (OP1) сдвигается на (OP3) разрядов также, как и в командах shr и shl но бит, вышедший за разрядную сетку, не обнуляется, а заполняется содержимым второго операнда, которым может быть только регистр.

Циклические сдвиги:

После выполнения команды циклического сдвига CF всегда равен последнему биту, вышедшему за пределы приемника.

Циклические сдвиги с переносом содержимого Флажка CF:

Для всех команд сдвига флаги ZF, SF, PF устанавливаются в соответствии с результатом. AF – не определен. OF – не определен при сдвигах на несколько разрядов, при сдвиге на 1 разряд в зависимости от команды:

- для циклических команд, повышенной точности и sal , shl флаг OF = 1, если после сдвига старший бит изменился;

- после sar OF = 0;

- после shr OF = значению старшего бита исходного числа.

BT <приемник>, <источник>

Пример использования команд усл. перехода, сравнения и циклов - student2.ru

4) Структуры в Ассемблере, их описание и использование.

Структура состоит из полей-данных различного типа и длины, занимая последовательные байты памяти. Чтобы использовать переменные типа структура, необходимо вначале описать тип структуры, а затем описать переменные такого типа. Описание типа структуры:

<имя типа> struc

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

------------------------

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

<имя типа> ends

<имя типа> - это идентификатор типа структуры, struc и ends - директивы, причем <имя типа > в директиве ends также обязательно. Для описания полей используются директивы определения данных и памяти: DB, DW, DD.Имя, указанное в этих директивах, является именем поля, но имена полей не локализованы внутри структуры, т.е. они должны быть уникальными в рамках всей программы, кроме того, поля не могут быть структурами – не допускаются вложенные структуры.

Например

TData struc ; TData – идентификатор типа

y DW 2000 ; y, m, d – имена полей. Значения, указанные

m DB ? ; в поле операндов директив DW и DB ,

d DB 28 ; называются значениями полей, принятыми

TData ends ; по умолчанию.

? – означает, что значения по умолчанию нет.

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

2б 1б 1б размеры полей в байтах

TData y m d

+0 +2 +3 смещение относительно начала

структуры.

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

имя переменной имя типа <нач. значения>

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

Нач-ым значением может быть: 1) ? 2) выражение 3) строка 4) пусто.

Например:

y m d

dt1 TData <?, 6, 4> ? 6 4

dt2 TData <1999, , > 1999 ? 28

dt3 TData < , , > 2000 ? 28

Идентификатор типа TData используется как директива для описания переменных также, как используются стандартные директивы DB, DW и т.д. Если начальные значения не будут умещаться в отведенное ему при описании типа поле, то будет фиксироваться ошибка. Правила использования начальных значений и значений по умолчанию:

- приоритетными являются начальные значения полей,

- при описании переменных, т.е. если при описании переменной для поля указан ? или какое-либо значение, то значения этих полей по умолчанию игнорируются.

Правила использования начальных значений и значений по умолчанию:

1) если в поле переменной указан знак ?, то это поле не имеет начального значения, даже если это поле имеет значение по умолчанию (поле y переменной dt1);

2) Если в поле переменной указано выражение или строка, то значение этого выражения или сама строка становится начальным значением этого поля (поля m и d переменной dt1 и поле y переменной dt2);

3) Если начальное значение поля переменной «пусто» - ничего не указано при описании переменной, то в качестве начального устанавливается значение по умолчанию – значение, указанное при описании типа, если же в этом поле при описании типа стоит знак ?, то данное поле не имеет никакого начального значения (поля m переменных dt2 и dt3).

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

Отсутствие начального значения отмечается запятой.

Если отсутствуют начальные значения нескольких последних полей, то запятые можно не ставить. Если отсутствуют значения первого поля или полей, расположенных в середине списка полей, то запятые опускать нельзя. Например:

dt4 TData <1980, ,> можно dt4 TData <1980>

dt5 TData <, , 5> нельзя заменить на dt5 TData < 5 >.

Если отсутствуют все начальные значения, опускаются все запятые, но угловые скобки сохраняются:

dt6 TData < >

При описании переменных, каждая переменная описывается отдельной переменной, но можно описать массив структур, для этого в директиве описания переменной указывается несколько операндов и (или) конструкция повторения DUP. Например:

dst TData <, 4, 1>, 25 DUP (< >)

Описан массив из 26 элементов типа TData, и первый элемент (первая структура) будет иметь начальные значения

2000, 4, 1, а все остальные 25 в качестве начальных будут иметь значения, принятые по умолчанию: 2000, ?, 28.

Имя первой структуры dst, второй – dst+4, третьей – dst+8 и т.д.

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

<имя переменной > . < имя поля>

Например, dt1.y, dt2.m, dt3.d

Ассемблер приписывает имени типа и имени переменной размер (тип), равный количеству байтов, занимаемых структурой

type TData = type dt1 = 4

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

; выполнить побайтовую пересылку dt1 в dt2

mov CX, type TData ; количество повторений в CX

mov SI, 0 ; i = 0

m: mov AL, byte ptr dt1[SI] ; побайтовая пересылка

mov byte ptr dt2[SI], AL ; dt1 в dt2

inc SI ; i = i+1

loop m ; использование byte ptr обязательно т.к. операторы разного типа

-----------------------------------

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

<адресное выражение> + <смещение поля в структуре>

Тип полученного адреса совпадает с типом поля, т.е.

type (dt1.m) = type m = byte

Адресное выражение может быть любой сложности, например:

1) mov AX, (dts+8).y

2) mov SI, 8

inc (dts[SI]).m ; Aисп = (dts + [SI]). m = (dts + 8).m

3) lea BX, dt1

mov [BX].d, 10 ; Aисп = [BX] + d = dt1.d

Замечания:

1) type (dts[SI]).m = type (dts[SI].m) = 1, но

type dts[SI].m = type dts = 4

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

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

Например: student struc

f DB 10 DUP (?) ; фамилия

i DB “ ******* “ ; имя

gr DW ? ; группа

oz DB 5, 5, 5 ; оценки

student ends

Описание переменных:

st1 student <“Petrov”, > ; нельзя, т.к. поле f не строка

st2 student < , “Petr”, 112, > ; можно, f – не имеет начального ; значения

st3 student < , “Aleksandra” >

; нельзя, в i 10 символов, а допустимо не больше 7.

Примеры программ с использованием данных типа структура.

; prim1.asm – прямое обращение к полям структуры

.model tiny

.code

org 100h ; обход 256 байтного префикса пр-го сегмента – PSP…

Start: mov AH, 9

mov DX, offset message

int 21h

;

lea DX, st1.s

int 21h

lea DX, st1.f

int 21h

lea DX, st1.i

int 21h

ret

;

message DB “ hello”, 0dh, 0ah, ”$”

tst struc ; описание типа структуры

s DB “student”,”$”

f DB “Ivanov “,”$”

i DB “Ivan “,”$”

tst ends

st1 tst < > ; описание переменной типа tst

end start

org 100h - все сегментные регистры вначале выполнения программы содержат адрес блока PSP, который резервируется непосредственно перед EXE и COM файлами. Смещением для 1-ой команды программы является адрес 100h. Переход на первую выполняемую команду и происходит с помощью директивы ORG 100h.

Prim2.asm – обращение к полям структуры в цикле

Model tiny

Code

org 100h ; обход 256 байтного префикса пр-го сегмента – PSP…

Start: mov AH, 9

Наши рекомендации