Программы на ассемблере

Изучение архитектуры персонального компьютера на примере микропроцессора фирмы Intel. Регистры общего назначения. Оперативная память; форматы данных и команд. Команд пересылки с различными способами адресации операндов. Структура программы на Ассемблере.

Рубрика Программирование, компьютеры и кибернетика
Вид курс лекций
Язык русский
Дата добавления 03.05.2014
Размер файла 506,4 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

std; Set Df, DF = 1

Программист может установить следующие флажки:

stc; CF = 1

clc; CF = 0

cmc; инвертировать флаг переноса

lahf; копирует младший байт регистра FLAGS а AH

sahf; из AH загружает флажки SF, ZF, AF, PF, CF

cli; IF = 0

sti; IF = 1

salc; установить регистр AL в соответствии с CF

Загрузка сегментных регистров

lds op1, op2

les op1, op2

lfs op1, op2

lgs op1, op2

lss op1, op2

Для всех команд op2 - переменная в ОП, размером в 32 или 48 бит в зависимости от разрядности операндов. Первые 16 бит этой переменной загружаются в соответствующий сегмент DS, ES и т.д., а следующие 16 или 32 - в регистр общего назначения, указанный в качестве первого операнда. В защищенном режиме значение, загружаемое в сегментный регистр, всегда должно быть правильным селектором сегмента, в реальном режиме любое число может использоваться как селектор.

Загрузка сегментных регистров

S1DB"ABC$"

ADRDDS1

lesDI, ADR

В переменную ADR записывается полный адрес, определяемый именем S1 (Seg:Ofs). В ES записывается значение сегментной части адреса S1, а в DI ее смещение.

Пример 1 использования команд работы со строками:

X DW 100 dup (?)

Y DW 100 dup (?)

Выполнить пересылку содержимого одной области памяти в другую

X = Y: -------------------------------------

CLD; DF = 0

lea SI, Y ; DS:SI - начало Y

push DS

pop ES

lea DI, X

mov CX, 100

repmovsw

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

Пример 2. В строке S, состоящей из 500 символов заменить первое вхождение звездочки на точку.

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

CLD; просмотр строки слева напрво

push DS

pop ES

lea DI, S

mov CX, 500

mov AL, ` * `

repne scasb; сканирование строки S и сравнение с (AL)

jne finish; ` * ` в строке нет

mov byte ptr ES:[DI - 1], ` . `

finish: --------------------------

Здесь используется выражение [DI - 1] т.к. после тогокак звездочка найдена DI увеличивается на 1 и указывает на следующий символ.

Строки переменной длины

Строка в языке Ассемблера может быть реализована по аналогии с тем, как это сделано в языке С/С++ и как в языке Паскаль. В С/С++ за последним символом строки располагают специальный символ с кодом, являющимся признаком конца строки. Изменение длины строки сопровождается переносом этого символа. Недостатком такого представления строк переменной длины заключается в том, что, например, для сравнения строк S1 и S2, длиной 500 и 1000 символов необходимо выполнить, может быть, 500 сравнений, хотя зная, что длина их различна, их можно было совсем не сравнивать. В Паскале строка представляется так:

Где n - текущая длина. Сколько места необходимо отводить под значение длины строки n - зависит от максимально возможной длины. Если она может состоять не более, чем из 255 символов, то под n достаточно одного байта. Тогда текущая длина строки содержится по адресу S, а ее i-ый символ по адресу S + i. Строку из 200 символов можно описать так:

S DB 201 dup (?)

Пример 3. Удалить из строки S первое вхождение символа звездочка.

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

; поиск ` * `

push DS ;

pop ES ; (ES) = (DS)

lea DI, S + 1; ES:DI = адресу S[1]

CLD; просмотр вперед

mov CL, S ; текущая длина строки

mov CH, 0 ; в CX

mov AL, ` * `

repne scasb ; поиск ` * ` в S

jne finish ; ` * ` в S нет, передаем управление на метку finish

; удаление ` * ` из S, сдвинуть S на 1 символ Si = Si+1

mov SI, DI ; DS:SI = адресу, откуда начинать пересылку

dec DI ; ES:DI = куда пересылать

rep movsb ; сдвиг "хвоста" S на 1 позицию влево

dec S ; уменьшить на 1 текущую длину

finish --------------------------

Представление и работа со списками в Ассемблере

Односвязный линейный связный представляют в виде:

Стандартных процедур для работы со списками в языке Ассемблера нет, их нужно реализовывать самим. Динамические переменные, располагаются в специальной области ОП, называемой кучей (heap). Размер кучи зависит от количества использованных в программе динамических переменных, будем считать от количества и длины списков.

Предположим, что для кучи достаточно 64 Кб, тогда пусть начало кучи определяет сегментный регистр ES. Если внутри кучи элемент списка имеет адрес (смещение) A, то абсолютный физический адрес этого элемента определяется адресной парой ES:A. И, так как в этих адресных парах для всех элементов общим является начало кучи ES, то будем считать адресом элемента списка 16-разрядное смещение А.

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

node struc ; тип элемента списка

elem DW ?; информационное поле

next DW ?; ссылочное поле

node ends

Если А описана с помощью директивы node: A node < >, то доступ к полям элемента списка с адресом А осуществляется так: ES: A.elem ; ES: A.next ;

Пустая ссылка - это адрес 0, определив константу NULL EQU 0, пользуемся для обозначения пустой ссылки константой NULL, как и в С++.

Ссылки на первые элементы списков описывают обычно в сегменте данных DS как переменные, размером в слово:

nsp DW ? ;

list DW ? ;

При работе со списками просматриваются элементы один за другим, так что необходимо знать адрес текущего элемента. Используем для хранения этого адреса регистр BX, причем в BX будет храниться только смещение текущего элемент адрес отсчитанный от начала кучи, поэтому, чтобы обратиться к элементу списка, необходимо использовать выражение ES: [BX], если укажем просто [BX], то по умолчанию этот адрес будет выбираться из сегмента DS. Обращение к полям текущего элемента это:

ES:[BX].elem и ES:[BX].next

Основные операции.

1) Анализ информационного поля:

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

mov AX, ES:[BX].elem ; сравнение информационного поля

cmp AX, X; со значением Х

je jes; если совпали, то переход на jes

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

2) Переход к следующему элементу:

mov BX, ES:[BX].next

3) Проверка на конец списка:

cmp BX, null

je list_end;

4) Поиск элемента с заданным значением информационного поля nsp - начало списка, x - искомая величина, в AL - результат = 1, если такой элемент в списке есть, или 0, если такого элемента

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

mov AL, 0

mov CX, x

mov BX, nsp ; BX = null, или адрес первого элемента

L:cmp BX, null

jeno ; если BX = null, то на метку no

cmp ES:[BX].elem, CX

jejes; [BX].elem = x, то на метку jes

mov BX, ES:[BX].next ; BX = BX.next

jmpL ; на повторение цикла пока не конец списка

jes:mov AL, 1

no:---------------------------

5) Вставка нового элемента в начало списка

В Ассемблере нужно самим написать процедуру new, которая выделяет место в куче для размещения нового элемента. Пусть такая процедура с именем new есть, она без параметров и результатом ее является адрес байта в куче, начиная с которого можно разместить новый элемент списка. Этот адрес передается вызывающей процедуре через регистр DI. Тогда вставить элемент в начало списка

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

call new ;

mov AX, x

mov ES: [DI].elem, AX

mov AX, nsp

mov ES: [DI].next, AX ;

mov nsp, DI

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

Удаление элемента из списка.

Пусть для адреса 1-го элемента используем BX, адрес 2-го элемента в DI и есть уже процедура dispose (di), удаляющую элемент из списка, т.е. освобождающую место в куче для дальнейшего использования, тогда удаление второго элемента можно реализовать так:

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

1) mov BX, nsp ; адрес первого элемента в BX

cmp BX, null ; if nsp = null, список пуст

je finish

2) mov DI, ES:[BX].next ; DI = null, или адресу 2-го элемента

cmp DI, null; если DI = null, 2-го элемента нет

je finish

3) mov AX, ES:[DI].next

3) mov ES:[BX].next, AX

call dispose; освобождение памяти

finish: ---------------------------

Организация "кучи" и процедур создания и удаления динамических переменных Организация "кучи" и процедур создания и удаления динамических переменных. При выполнении программы, занятые и свободные ячейки в куче, располагаются не последовательно, а произвольно, так как различные элементы списка могут удаляться и также произвольно создаваться. Чтобы определить какие же ячейки кучи свободны, удобнее всего все свободные ячейки кучи объединить в один список. Его называют списком свободной памяти (ССП). Адрес начала списка хранится в фиксированной ячейке с именем heep_ptr. Если программе необходимо место под очередной элемент в некотором списке, это место выделяется из ССП, если удаляется некоторый элемент, то он добавляется к ССП. Т.Е. ССП можно представить как обычный список, для простоты с элементами такой же структуры.

Осталось определить где располагается переменная heap_ptr - указатель на ССП. Лучше всего отвести ей место в самом начале кучи, в ячейке с относительным адресом 0.

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

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

Heap_size EQU n ; n - количество элементов в списке

heap segment

Heap_ptr DW ? ; ячейка с начальным адресом ССП

DD heap_size dup (?) ; n слов в куче

Heap ends

Так описали сегмент кучи, адрес начала кучи должен храниться в регистре ES и программист сам должен загрузить его в этот сегмент. Кроме того, байты этого сегмента нужно объединить в список ССП, например, так чтобы первая ячейка была первым элементом ССП и т.д. Heap_ptr имеет нулевой относительный адрес heap_ptr, последний элемент в ССП имеет смещение 4*n - 2. Инициализация кучи и загрузка ее начала в ES

init_heapproc far

push SI

push BX

push CX

; установка ES на начало кучи

mov CX, heap

mov ES, CX

; объединение всех двойных слов в ССП

mov CX, heap_size

mov BX, null

mov SI, 4*heap_size - 2

in1:mov ES:[SI].next, BX

mov BS, SI

sub SI, 4

loop in1

mov ES:heap_ptr, BX

pop CX

pop BX

pop SI

ret

init_heapendp

К процедуре init_heap необходимо обращаться до обращения к процедурам new и dispose. Процедура создания динамической переменной:

;на выходе процедуры в DI будет адрес нового элемента

newproc far

mov DI, ES:heap_ptr ; DI = null или адресу 1-го эл-та

cmp DI, null

je empty_heap ; если ССП пуст, empty_heap

push ES:[DI].next

pop ES:heap_ptr ; указатель на второй элемент кучи

ret

empty_heap: lds DX, CS:aerr ; реакция на пустую кучу

; DS:DX - адрес сообщения об ошибке

outstr ; макрос вывода этого сообщения

finish ; макрос останова программы

aerrDD err ; абсолютный адрес сообщения

errDB `ошибка в new: исчерпание кучи','$'

newendp

Процедура освобождения динамической памяти dispose

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

disposeproc far

; на входе адрес удаляемого элемента в регистре DI

push ES:heap_ptr

pop ES:[DI].next ; DI.next = heap_ptr

mov ES:heap_ptr, DI ; heap_ptr = DI

ret

disposeendp

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

20. Макросредства языка Ассемблер

Макросредства называют самым мощным средством программирования в Ассемблере. Они позволяют генерировать, модифицировать текст программы на Ассемблере в процессе трансляции программы. К макросредствам относят: блоки повторений, макросы, команды условной генерации. Программы, написанные на макроязыке, транслируются в два этапа. Сначала она переводится на "чистый" язык Ассемблера, т.е. преобразуется к виду, в котором нет никаких макросредств, этот этап называют макрогенерацией. Затем выполняется ассемблирование - перевод в машинные коды. Макрогенерацию называют ещё препроцессорной обработкой.

Блоки повторения в процессе макрогенерации заменяются указанной последовательностью команд столько раз, сколько задано в заголовке блока, причем набор команд может повторяться в неизменном или модифицированном виде, в зависимости от вида заголовка блока. Набор команд повторяется n раз в том месте программы, где указан блок повторения. Макросы более похожие на ПП. Аналогично ПП существует описание макроса и обращение к нему. Описание макроса называют макроопределением, а обращение - макрокомандой. Процесс замены макрокоманды на макрос - макроподстановкой, а результат этой подстановки - макрорасширением. Макроопределение не порождает никаких машинных команд, оно должно предшествовать первой макрокоманде, использующей это макроопределение, и может располагаться как непосредственно в тексте программы, так и может быть подключено из другого файла с помощью директивы INCLUDE <имя файла>. Основное отличие макроса от процедуры заключается, во-первых, в том, что при обращении к ПП управление передаётся на участок памяти, в котором содержится описание ПП, а при обращении к макросу его тело (макроопределение) вставляется на место макрокоманды, т.е. сколько раз мы обратимся к макросу, сколько макрокоманд будет в программе, столько раз повторится макроопределение, вернее, макрорасширение. Макрос "размножается", увеличивая размер программы. Таким образом, применение процедур дает выигрыш по памяти, но использование макросов дает выигрыш по времени, т.к. нет необходимости передавать управление в ПП и обратно (CALL и RET), а также организовывать передачу параметров. Рекомендация: если повторяются большие фрагменты программ, лучше использовать процедуры, если относительно небольшие, то макросы. Второе отличие заключается в том, что текст процедуры неизменен, а содержание макрорасширения зависит от параметров макрокоманды, если используются директивы условной генерации, и тогда это существенно.

Общий вид блока повторений:

<заголовок>

<тело>

endm

<тело> - любое количество любых операторов, предложений, в том числе и блоков повторений. endm определяет конец тела блока. Количество повторений тела и способ модификаций тела блока зависит от заголовка. Возможны следующие заголовки:

1) REPT n ; n - константное выражение

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

N EQU 8 N EQU 8

REPT N-6 DB 0,1

DB 0,1 DW ?

DW ? DB 0,1

еndm DW ?

Для создания массива с начальными значениями от 0 до 0FFH достаточно написать блок повторений:

n = 1

mas DB 0 ; имя массива mas

Rept 255 ; начало блока

DB n

n = n + 1

endm

2) Второй вид заголовка:

IRP P , <V1,V2,…Vk> ; < и > обязательные символы

<тело> ; тело повторяется k раз так, что в i-той копии

еndm

формальный параметр Р замещается фактическим параметром Vi. Формальный параметр Р - это локальное имя, не имеющее смысла вне блока. Если оно совпадает с именем другого какого либо объекта программы, то в теле блока это просто имя, а не этот объект. Например:

a) IRP reg, <AX, BX, CX,SI> После макрогенерации

push reg push AX

endmpush BX

> push CX

push SI

b) IRP BX , <5,7,9> add AX , 5

add AX, BX > add AX , 7

endm dd AX , 9

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

c) IRP R , <dec word ptr, L: inc word ptr>

R W dec word ptr W

jmp M > jmp M

endm L: inc word ptr W

jmp M

Здесь параметром является имя команды и тип операнда.

3) Вид заголовка: IRPC P , S1S2….SK

IRPC P , S1S2….SK

<тело>

еndm

P - формальный параметр, Si -символы, любые, кроме пробелов и точки с запятой, если необходимо использовать здесь пробел или точку с запятой, то надо всю последовательность символов записать в угловых скобках. Встречая такой блок, макрогенератор заменяет его на k копий тела так, что в i-той копии параметр Р заменен на символ Si. Например:

IRPC A, 175P add AX , 1

add AX, A > add AX , 7

endm add AX , 5

add AX , P

Макрооператоры.

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

1) & - амперсанд - используется для того, чтобы указать границы формального параметра, выделить его из окружающего текста, при этом в текст программы он не записывается. Например:

а) IRP W, <1,5,7> var1 DW ?

VAR&W DW? > var5 DW ?

endm var7 DW ?

б) IRPC A, ? < DB ?A, ?, ?B?

DB ?A, &A, &A&B? > DB ?A, <, <B

endm

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

Например:

…………………………..

IRPC P1, AB IRPC P2, HL inc AH

IRPC P2, HL inc A&P2 inc AL

inc P1&&P2 > endm > inc BH

endm IRPC P2, HL inc BL

endm inc B&P2

endm

2) Макрооператор < > - угловые скобки действует так, что весь текст, заключенный в эти скобки, рассматривается как одна текстовая строка, и в неё могут входить пробелы, запятые и другие разделители. Этот макрооператор часто используется для передачи текстовых строк в качестве параметров для макросов и для передачи списка параметров вложенному макроопределению или блоку повторений.

а) IPR V , <<1,2>,3> DB 1,2

DB V > DB 3

endm

b) IRPC S, <A; B> DB ?A?

DB ?S? > DB ? ; ?

endm DB ?B?

Если в примере б) скобок < > не будет, то символ В будет восприниматься как комментарий после точки с запятой.

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

4) Макрооператор % - процент указывает на то, что следующий за ним текст является выражением, которое должно быть вычислено, и результат передается как параметр. Например:

K EQU 4

………… DW k+1

IRP A, <k+1, % k+1, W% k+1> DW 5

DW A > DW W5

endm

5) Макрооператор ;; - две точки с запятой определяют начало макрокомментария. Текст макрокомментария не включается в макрорасширения и в листинг программы.

Макросы.

Описание макроса, макроопределение, имеет вид:

<имя макроса> Macro <формальные параметры>

LOCAL <список имен>

<тело>

endm

Первая строка - это заголовок макроса, имя макроса будет использоваться для обращения к этому Макроопределению. Формальные параметры записываются через запятую, это локальные имена, никак не связанные с объектами программы. Количество локальных параметров не ограничено, но они должны умещаться в одной строке. Поскольку на место каждой Макрокоманды записывается Макрорасширение, кроме того, одни и те же метки могут использоваться и в самой программе, чтобы не возникало ошибки "метка уже определена", директива LOCAL <список имен> перечисляет через запятую имена меток, которые будут использоваться в теле макроса.

<тело> - это копируемый фрагмент программы, любое количество любых предложений Я.А., в которых используются формальные параметры.

Макрокоманда - обращение к макросу:

<имя макроса> <фактические параметры>

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

С помощью директивы EXITM можно осуществить досрочный выход из макроса, если использовать команды условной генерации IF x … endif.

C помощью директивы PURGE <имя макроса> можно отменить определенный ранее макрос. Эта директива часто используется сразу после директивы INCLUDE, включившей в текст программы файл с большим количеством готовых макроопределений.

Примеры макросов

Использование макросов позволяет составлять программу в терминах более крупных операций. Опишем в виде макроса оператор IF x< y then GOTO L.

IF_L MACRO x, y, L

mov AX, x

cmp AX, Y

jl L

endm

Используя этот макрос, поиск минимального из 3-х чисел запишется так:

; DX = min (A,B,C)

mov DX, A

IF_L A, B, M1

mov DX, B

M1:IF_L DX, C, M2

mov DX, C

M2: ----------------------

После макрогенерации в программе будет текст:

mov DX, A

mov AX, A

cmp AX, B

jl, M1

mov DX, B

M1:mov AX, DX

cmp AX, C

jl M2

mov DX, C

M2: ------------------------------

2) Обращение к процедурам будет нагляднее, если передачу параметров оформить как макрос. Например: Вычислить CX = NOD(A,B) + NOD(C,D), если есть процедура вычисления NOD(x,y), результат ее в АХ.

CALL_NOD MACRO x, y

mov AX, x

mov BX, y

call NOD ; (AX) = NOD(x, y)

endm

CALL_NOD A, B ; наглядное обращение к ПП с параметрами.

mov CX, AX ; (CX) =NOD(A,B)

CALL_NOD C, D ; (AX) = NOD(C,D)

add CX, AX ; (CX) = NOD(A,B) + NOD(C,D)

Использование меток в макросах.

Пример 1. Если в макроопределении используются метки, но нет директивы Local , то после макрогенерации будет сообщение об ошибке - дублирование меток:

макроопределение макрокоманда макрорасширение …………

M Macro M > L: ------------

………… …………

L: ---------------- -----------------------

endm …………

M > L: ------------

…………

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

MD Macro R1, R2 ; r1 = r1 mod r2

Local M, M1

M: cmp R1, R2 ; while r1 >= r2 DO r1 = r1 - r2

jb M1

sub R1, R2

jmp M

M1:

endm

Обращения к макросу MD:

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

1) MD AX, BX ; (R1 > AX, R2 > BX)

?? 0000 : cmp AX, BX

jb ?? 0000

sub AX, BX

jmp ?? 0000

?? 0001: ----------------

2) MD CX, DX ; (R1 > CX, R2 > DX)

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

?? 0002 : cmp CX, DX

jb ?? 0003

sub CX, DX

jmp ?? 0002

?? 0003: ---------------------

Макрогенератор, встретив директиву Local M, M1, будет заменять метки M и M1 на специальные имена вида ??хххх, где хххх - четырехзначное 16-ричное число от 0000?FFFF.

Директивы условного ассемблирования (ДУА).

ДУА управляют процессом ассемблирования путем подключения или отключения фрагментов исходного текста программы. Общий вид:

1) if <выражение>

if- часть

[ else

else-часть ]

endif

2) if <выражение >

if-часть

elseif <выражение 1>

elseif-часть 1

elseif <выражение 2>

elseif-часть 2

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

[ else

else-часть ]

endif

ДУА в форме 2) используется аналогично операторам выбора в языках высокого уровня. ДУА много, рассмотрим некоторые из них:

1) if <константное выражение> if-часть

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

2)а) ife <константное выражение >

в) elseife <константное выражение>

if-часть работает, если выражение ложно, равно нулю.

3) a) ifdef метка; if-часть работает, если

b) elseifdef метка; указанная метка определена

4) a) ifndef метка; if-часть работает, если

b) elseifndef метка; указанная метка не определена

5) a) ifb <аргумент>; if-часть работает, если

b) elseifb <аргумент>; значением аргумента является пробел

6)a) ifnb <аргумент>; if-часть работает, если значением

b) ifnb <аргумент> ; аргумента является не пробел

7) a) ifdif <арг1>, <арг2> ; if-часть работает, если аргументы различны, прописные и строчные буквы различаются

b) elseifdif <арг1>, <арг2> ;

8)a)ifdifi <арг1>, <арг2> ; ------------------------------прописные

b) elseifi <арг1>, <арг2>; и строчные буквы не различаются

9) a) ifidn <арг1>, <арг2> ; if-часть работает, если аргументы

b) elseifidn <арг1>, <арг2> ; одинаковы, прописные и строчные ; буквы различаются

10) a) ifidni <арг1>, <арг2>; -----------------, прописные и строчные

b) elseifidni <арг1>, <арг2> ; буквы не различаются

Здесь угловые скобки обязательны.

Примеры использования ДУА .

1) Использование ДУА непосредственно в Ассемблере. При отладке большой программы обычно используются отладочные печати для проверки правильности работы отдельных ее участков. В отлаженной программе эти печати удаляются. Но если отладка выполняется в несколько этапов, то добавлять печати в программу и исключать их - это тоже громоздкая работа, во время которой можно внести новые ошибки.

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

debug EQU 1 - отладка, debug EQU 0 - счет

а в программе должно быть:mov x, AX

if debug

OutInt x

endif

mov BX

После макрогенерации в программе появится текст

если debug < > 0: mov x, AX если debug = 0: mov x, AX

OutInt x mov BX, 0

mov BX, 0

Здесь OutInt - макрокоманда обращения к процедуре вывода. Решить задачу, чтобы отладочная печать работала в режиме отладки и не работала при счете, можно и с помощью команды сравнения и условного перехода:

mov x, AX

mov CL, debug

cmp CL, 1

jne L

OutInt x

L:mov BX, 0

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

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

Использование ДУА в макросах

Пример 1. Опишем в виде макроса операцию сдвига значения переменной x на n разрядов вправо. n - явно заданное положительное число. Макрорасширение должно содержать минимально возможное число команд. Это можно сделать так:

shiftmacro x, n

ife n - 1; n - 1 = 0 ?

shr x, 1

else; n > 1

mov CL, n

shr x, CL

endif

endm

Обращения: shift A, 5; x = A, n = 5

После макрогенерации:

mov CL, 5

shr A, CL

Пример 2

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

Константное выражение часто бывает логическим, в нем могут использоваться операторы отношения: EQ, NE, LT, LE, GT, GE и логические операторы NOT, OR, XOR. Запишем в виде макроса SET_0 x операцию x = 0, если x - переменная размером в байт, слово или двойное слово.

SET_0 macro x

if type x EQ dword

mov dword ptr x, 0

elseif type x EQ word

mov word ptr x, 0

else mov byte ptr x, 0

endif

endm

Напишем еще одно макроопределение для сдвига вправо на n разрядов значения байтовой переменной B. Учтем, что при n = 0 сдвига нет и макрорасширение не должно появиться в тексте программы, а при n > 7 результат сдвига - это 0, поэтому сдвиг можно заменить записью нуля в B.

Set_0macro B, n

if (n GT 0) AND (n LT 8) ;; 0 < n <8

mov CL, n

shr b, CL

else

if n GT 8;; n >= 8

mov B, o

endif

endif

endm

Здесь использовались вложенные if….endif и в макроопределениях комментарий записывается после двух двоеточий.

Пример 4 использование ifidn и ifdif

Поиск max или min из двух знаковых величин, хранящихся в байтовых регистрах, т.е. вычислить R1 = T (R1, R2), где T - это max или min, причем, должно генерироваться непустое макрорасширение только если R1 и R2 - это разные регистры. Если обращение к макросу будет Max_Min R1, R2, T, то необходимо проверять несовпадение первых двух параметров. И чтобы один макрос вычислял и max и min, нужно проверять и значение третьего параметра. Макрос может быть таким:

Max_Min macro R1, R2, T

local L

ifdif <R1>, <R2> ;; R1 и R2 - разные регистры

cmp R1, R2

ifidn <T>, <max> ;; T = max ?

jge L

else

jle L

endif

mov R1, R2

L: endif

endm

Макрокоманда Max_Min AL, BH, MIN приведет к следующим действиям макрогенератора: (пусть метка L заменилась меткой вида ??0110)

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

ifdif <AL>, <BH>cmp AL, BH в исходном тексте

cmp AL, BHifidn <MIN>, <MAX> программы

ifidn <MIN>, <MAX> jge ??0110 окажется

jge ??0110else cmp AL, BH

else jle ??0110 jle ??0110

jle ??0110endif mov AL, BH

endif mov AL, BH??0110:

mov AL, BH??0110:----------------------

??0110: ----------------------------

endif

Пример многомодульной программы

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

masm p.asm, p.obj, p.list

linkp.obj + ioproc.obj, p.exe

p.exe

Есть файл io.asm, содержащий описания макросов обращения к этим процедурам. Этот файл подключается на этапе ассемблирования с помощью директивы include io.asm. Для иллюстрации организации многомодульной программы решим задачу: ввести в текст не более, чем из 100 символов, заканчивающийся точкой и вывести его в обратном порядке, заменив прописные буквы на строчные. Эту задачу можно решить проще, но….

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

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

; вспомогательный модуль

public EOT, LOWLAT

D1 segment

EOT DB `.'; симвл конца ввода

D1 ends

C1 segment

assume CS: C1

LOWLAT proc far

; процедура перевода больших букв в малые,

; на входе (AL) - любой символ, на выходе (AL) - малая буква

cmp AL, `A' ; AL < `A' или AL > `Z', то nolat

jb nolat

cmp AL, `Z'

ja nolat

add AL, - `A' + `a'

nolat: ret

LOWLAT endp

C1 ends

end

; головной модуль

include io.asm

extrn EOT: byte, LOWLAT: far

s segment stack

DB 256 dup (?)

sends

dsegment

txt DB 100 dup (?), `$'

d ends

c segment

assume SS: s, DS: d, CS: c

start: mov AX, d

mov DS, AX

mov AX, seg EOT

mov ES, 100

OutCH `>'; приглашение к вводу символа

inp: InCH AL; ввод символа

cmp AL, ES:EOT; если достигнут конец ввода

je PR; то PR

call LOWLAT; замена символа

dec SI

mov TXT[SI], AL

jmp INP

PR: lea DX, TXT[SI]; вывод

OutSTR; на экран TXT

Finish

c ends

end start

В основной программе OutCH <параметр> и InCH <параметр> - макрокоманды ввода и вывода на экран параметра, OutSTR - макрокоманда вывода строки. Finish - это:

Finish macro; макрос окончания счета

mov AH, 4Ch

int 21h

endm

Размещено на Allbest.ru


Подобные документы

  • Ассемблер как символический аналог машинного языка. Архитектура микропроцессора: организация памяти, способы адресации операндов, правила использования регистров. Текст программы. Этапы программирования на ассемблере, алгоритмы выполнения задач.

    контрольная работа [515,1 K], добавлен 20.01.2016

  • Внутренняя архитектура микропроцессора Intel 486. Формат данных и команд. Регистры общего назначения. Программная модель устройства FPU, регистр флагов. Разработка структуры и микропрограммы микропроцессора, управляющего автомата с жесткой логикой.

    курсовая работа [1,6 M], добавлен 27.05.2013

  • Изучение базовых команд ПК на базе МП i286 и их форматов. Изучение прямых способов адресации данных. Наработка практических навыков работы с командами. Разработка регистровой модели выполнения операций передачи данных. Программа реализации команд.

    контрольная работа [42,2 K], добавлен 12.03.2011

  • Функциональная схема микропроцессора Intel 8086 (i8086). Формирование физического адреса памяти, выборка команд из памяти и запись их в очередь команд. Система команд процессора. Суть защищенного режима, переход из защищенного режима в реальный режим.

    практическая работа [93,3 K], добавлен 24.03.2013

  • Типы команд, синтаксис ассемблера и код операции, по которому транслируется команда. Команды вычисления и непосредственной пересылки данных между регистрами. Поле для определения операции вычисления. Управление последовательностью выполнения программы.

    реферат [29,1 K], добавлен 13.11.2009

  • Краткий обзор процессоров фирмы intel. Основные характеристики i80286: режим реальной адресации, режим защиты, сопроцессор i80287, условия программирования i80287. Основные характеристики i80386: 32-битная архитектура, способы адресации.

    курсовая работа [29,9 K], добавлен 23.06.2007

  • Модель целочисленного MMX-расширения и особенности работы сопроцессора. Отображение ММХ-регистров на регистры стека сопроцессора. Система команд MMX: команды пересылки, сложения и вычитания, сравнения, логических операций, сдвига, упаковки и распаковки.

    презентация [240,3 K], добавлен 11.12.2013

  • Изучение элементов структуры микропроцессора i80386 и алгоритмов выполнения множества команд. Разработка проекта структуры АЛУ и структуры микро-ЭВМ на базе гипотетического процессора. Описание и создание программы эмуляции по выполнению заданных команд.

    курсовая работа [484,4 K], добавлен 07.09.2012

  • Характеристика регистров памяти как устройств временного хранения данных. Различия между прерываниями и исключениями команд, их обработка. Вычисление производительности ЭВМ. Программа с использованием отложенного запуска команд. Виды компьютерных сетей.

    контрольная работа [24,9 K], добавлен 09.11.2010

  • Архитектура микроконтроллеров семейства Mega. Организация памяти. Способы адресации памяти данных. Энергонезависимая память данных. Таблица векторов прерываний. Счетчик команд и выполнение программы. Абсолютный вызов подпрограммы. Сторожевой таймер.

    дипломная работа [213,9 K], добавлен 02.04.2009

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.