Помощь в написании студенческих работ
Антистрессовый сервис

Ассемблер для IBM PC

МетодичкаПомощь в написанииУзнать стоимостьмоей работы

Где PROC — директива, определяющая начало процедуры, <�имя> — метка, служащая именем процедуры и задающая адрес точки входа в процедуру; <�тип> — параметр, определяющий тип процедуры и может принимать два значения: near (ближний) и far (дальний). Если используется упрощенные формы определения сегментов, то тип процедуры задается выбранной моделью памяти и его можно не указывать. Для моделей tiny… Читать ещё >

Ассемблер для IBM PC (реферат, курсовая, диплом, контрольная)

Ассемблер для IBM PC.

Данная разработка является второй частью методического руководства к выполнению лабораторных работ. В нее вошли вопросы, касающиеся обработки символьной информации, работы с процедурами, выполнения логических битовых операций. Разработка составлена на основе лекций, читаемых авторами по курсу «Архитектура вычислительных систем и сетей», «Организация ЭВМ и систем», «Введение в язык Ассемблера».

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

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

· цель работы;

· основные сведения — содержат минимальных набор теоретических сведений, необходимых в ходе выполнения работы;

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

· варианты заданий для индивидуальной работы;

· контрольные вопросы.

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

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

1. Обработка символьной информации.

Цель: Изучить команды для обработки строк, приемы, используемые в работе со строками, рассмотреть приемы их использования, реализовать приведенные базовые операции при решении задач.

Задачи:.

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

ь Изучить синтаксис и использование префиксов повторений: REP, REPE и REPNE.

ь Изучить синтаксис и использование команд:

o пересылки строк MOVS, LOADS, STOS и их эквивалентные формы;

o проверки строк CMPS и его эквивалентную форму;

ь Научиться приемам обработки строк.

Цепочечные или строковые команды..

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

Особенности строковых команд..

1. Каждая строковая операция представлена двумя командами: одна из них предназначена для обработки строк из байтов (мнемокод содержит букву b (byte)), а другая — для обработки строк из слов (мнемокод содержит букву w (word)). В целом действия этой пары команд совпадают, поэтому обычно про них говорят как про одну команду, и в случае необходимости уточняют, какой именно вариант ее имеют в виду.

2. Для выполнения своих функций строковые команды используют определенные регистры. Полные физические адреса для операндов строковых команд следующие: адрес источника src — пара DS: SI, адрес приемник dst — пара ES: DI.

3. Все строковые команды по завершении основного действия выполняют изменение регистров SI и DI так, чтобы в них оказались адреса соседних элементов строк (на величину d).

4. Направление просмотра строки зависит от значения флага направления DF. Изменить флаг DF можно командами:

очистка флага DF (clear DF) — CLD (DF:=0) — просмотр слева направо;

установка флага DF (set DF) — STD (DF:=1) — просмотр справа налево.

Существует пять основных строковых команд: загрузка (LODS), запись (STOS), пересылка (MOVS), сканирования (SCAS) и сравнения (CMPS), которые можно разделить на группы:

команды пересылки строк: MOVS — пересылка, LOADS — загрузка, STOS — запись;

команды проверки строк: SCAS — сканирование, CMPS — сравнение.

Перечень команд обработки строк представлен в таблице 1.

Замечание. Алгоритм работы команды CMPS заключается в последовательном выполнении вычитания над очередными элементами обеих строк. По результатам вычитания изменяется содержимое регистра флага, но при этом не меняется информация в ячейках памяти, адресуемые регистрами SI и DI. Если строка-источник src меньше, чем строка-приемник dst, то CF = 1. Если строки равны, то ZF = 1. Если строка-источник src больше, чем строка-приемник dst, то CF = 0 и ZF = 0. В этих командах могут быть использованы префиксы повторения REPE — повторить пока dst = src или REPNE — повторить пока dst <> src.

Таблица 1. Строковые команды.

Мнемокод.

Действие.

Операнд 1.

Операнд 2.

Примечание.

CMPS.

Сравнение пары элементов:

[DS:SI]=[ES:DI]?; SI:=SI+d; DI:=DI+d,.

Регистры DS и SI.

Регистры ES и DI.

Записывается без операндов. По результатам сравнения изменяется регистр флагов.

SCAS.

Сканирование строки (сравнения значения аккумулятора AL/AX с байтом / словом в памяти).

AL=[ES:DI]?; DI: — DI±1.

Регистры ES: DI.

AL.

Используется для поиска в строке элемента, равного заданному (в AL или АХ) или отличного от заданного.

MOVS.

Пересылка строки:

[DS:SI] => [ES:DI];

SI:=SI+d; DI:=DI+d.

Источник — регистры DS и SI.

Приемник — ES и DI.

Не меняет флаги и потому выход из цикла возможен только по СХ=0.

STOS.

Перенос элементов из аккумулятора в строку-приемник dst: AL[ES:DI].

регистра AL.

регистров ES: DI.

Используется для записи во все ячейки какой-то области памяти одной и той же величины, указанной в регистре AL или АХ.

LODS.

Перенос элементов из строки-источника src в аккумулятор: [DS:SI] AL.

регистрами DS: SI.

регистр AL (AX).

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

В таблице 2 приведены условные переходы, которые можно использовать с командой CMPS.

Таблица 2. Условные переходы для команд сравнения.

Условие.

Без знака.

Со знаком.

src < dst.

JB.

JL.

src <= dst.

JBE.

JLE.

src <> dst.

JNE (JNZ).

JNE (JNZ).

src = dst.

JE (JZ).

JE (JZ).

src >= dst.

JAE.

JGE.

src > dst.

JA.

JG.

Команды префикса повторения..

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

ь rep (repeat) — повторять, пока CX > 0; используется с командами, реализующими операции-примитивы пересылки (movs) и сохранения элементов цепочек (stos);

ь repe или repz (repeat while Equal or Zero) — повторять, пока флаг нуля установлен и CX > 0; используются с командами сравнения (cmps) и сканирования (scas) для поиска отличающихся элементов цепочек;

ь repne или repnz (repeat while Not Equal or Zero) — повторять, пока флаг нуля сброшен и CX > 0; используются с командами сравнения и сканирования для поиска совпадающих элементов цепочек.

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

Примеры программ, реализующих действия со строками..

Фрагмент программы копирования 10 байт из поля отправителя source в поле получатель dst.

data.

src DB `ABCDEFGHIJ'; строка-источник.

dst DB 10 dup (?); строка — приемник.

code.

ASSUME DS: @data, ES: @data.

Main:

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

MOV DS, AX; настройка DS на адрес сегмента данных.

MOV ES, AX; настройка ES на адрес сегмента данных.

LEA SI, src; поместить в SI смещение строки-источника src.

LEA DI, dst; поместить в DI смещение строки-приемника dst.

MOV CX, 10; длина строки.

CLD; по возрастанию адресов.

REP MOVS dst, src; повторить пока CX > 0.

Examle 7.1. Фрагмент программы сканирования буфера buffer, со сбросом старшего бита каждого байта и сохранением результата в output.

data.

buffer DB 0C8h, 0FBh, 0F5h, 0Cah, 41h, 32h, 43h. 04h, 87h, 8Ch.

output DB 10 DUP (?).

code.

.

CLD.

MOV SI, OFFSET buffer; буфер-источник.

MOV DI, OFFSET output; буфер-приемник.

MOV CX, 10; длина буфера.

L:

LODS buffer; копировать DS: SI в AL.

AND AL, 7FH; очистить старший бит.

STOS output; сохранить AL в ES: DI.

LOOP L; повторить пока CX <> 0.

Сравнить две строки S1 и S2 каждая длиной N.

.

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

LEA SI, S1; в DS: SI поместить начало S1.

LEA DI, S2; в ES: DI поместить начало S2.

MOV CX, N; в CX длина строк.

L:

CMPSB; сравнить пару элементов.

JNE NOEG; если S1<>S2, то NOEG.

LOOP L; к следующей паре.

EQ:

…; действия, если S1 = S2.

NOEG:

…; действия, если S1 <> S2.

В строке S из 500 символов заменить первое вхождение символа '*' на точку.

CLD; просмотр строки вперед.

PUSH DS;

POP ES; установить ES на сегмент данных.

LEA DI, S; ES: DI=начало S.

MOV СХ, 500; длина строки.

MOV AL, '*'; символ для поиска.

REPNE SCASB; поиск первого вхождения '*' в S.

JNE FIN; в строке S нет вхождения '*'.

MOV BYTE PTR ES: [DI-1], '.'; замена `*' на точку.

FIN:…

Практическая часть..

Составить программу, реализующую следующие действия (по вариантам).

1. Ввести с клавиатуры строку. Сжать строку, т. е. удалить пробелы и табуляции. Вывести результаты на экран.

2. Ввести с клавиатуры строку. Посчитать количество слов в строке. Вывести результаты на экран.

3. Ввести с клавиатуры строку. Ввести с клавиатуры коротенькую строку — шаблон. Найти шаблон во введенной строке. Вывести на экран «ДА», если шаблон есть, и «НЕТ», если его нет.

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

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

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

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

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

9. Дана строка символов (введена с клавиатуры). Сформировать новую строку из исходной путем заданного числа повторений исходной строки.

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

11. Инвертировать заданную строку.

12. Найти максимальный и минимальный символы в исходной строке.

13. Удалить из исходной строки повторные вхождения заданного символа.

14. Удалить из исходной строки заданную конфигурацию символов.

Контрольные вопросы и задания..

1. Назовите строковые команды, выполняемые текстовым редактором, которые могут быть реализованы на языке ассемблера.

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

3. Реализуете процедуру копирования данных с использованием команд MOVSB и MOVSW.

4. Реализуете процедуру копирования данных по убыванию адресов.

5. Реализуете процедуру копирования данных без использованием цепочечных команд копирования.

6. Выясните, что будет, если в SI поместить смещение строки dst, а в DI строки src.

7. Можно ли вместо префикса REP использовать другой, например REPE. Если, да, то почему.

8. Имеется следующее определение данных:

DATASG SEGMENT PARA.

CONAME DB `SPACE EXPLORES INC.'.

PRLINE DB 20 DUP («`).

Используя цепочечные команды, выполните (запишите фрагмент программы):

a). Пересылку данных из CONAME в PRLINE слева направо.

b). Пересылку данных из CONAME в PRLINE справа налево.

c). Загрузку третьего и четвертого байта области CONAME в регистр AX.

d). Сохранение содержимого регистра AX по адресу PRLINE + 5.

e). Сравнение данных в областях CONAME и PRLINE.

f). Сканирование области CONAME и поиск в ней символов «пробел». Если символ найден, то переслать его в регистр BH.

9. Сравнить командой cmps две цепочки байт в памяти string1 и string2 и поместить первый несовпавший байт из string2 в регистр al. Для загрузки этого байта в регистр-аккумулятор al использовать команду lods.

2. Процедуры в языке Ассемблера.

команда ассемблер подпрограмма строка.

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

Задачи:.

ь изучить механизм работы команды вызова подпрограммы CALL, возврата из подпрограммы RET, правила оформления подпрограмм;

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

Команды работы подпрограммы..

В языке ассемблера подпрограмма оформляется в виде процедур. Для объявления процедур в одномодульных, простых программах можно использовать упрощенный вариант синтаксиса:

<�имя> PROC <�тип>

<�тело процедуры>

RET.

<�имя> ENDP.

где PROC — директива, определяющая начало процедуры, <�имя> — метка, служащая именем процедуры и задающая адрес точки входа в процедуру; <�тип> — параметр, определяющий тип процедуры и может принимать два значения: near (ближний) и far (дальний). Если используется упрощенные формы определения сегментов, то тип процедуры задается выбранной моделью памяти и его можно не указывать. Для моделей tiny, small и compact определяется тип near, а для остальных — far; RET (Return) — последняя команда подпрограммы. Она осуществляет выход из подпрограммы и возврат в основную программу. Тип процедуры автоматически задает тип возврата из процедуры.

Вызов подпрограммы из основной программы осуществляется командой CALL (), которая имеет следующий синтаксис:

CALL <�тип> <�имя>

где <�тип> — параметр, определяющий тип перехода и может принимать значения near или far; <�имя> — имя вызываемой процедуры.

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

Фрагмент программы вызова процедур

; фрагмент кода программы.

main PROC.

MOV AX, @data.

MOV DS, AX.

CALL MySub.

MOV AX, 4C00h.

INT 21.

main ENDP.

MySub PROC.

RET.

MySub ENDP.

Передача параметров в процедуру..

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

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

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

Пример. 1. Вычислить c=max (a, b)+max (5, a-l), где все числа — знаковые размером в слово. Вычисление max (х, у) описать как процедуру. Условия передачи параметров: первый параметр (х) — через регистр АХ, второй параметр (у) — через регистр ВХ, результат (max) — в регистре АХ.

При этих условиях процедура и соответствующий фрагмент основной программы выглядят следующим образом: (для примера опишем процедуру как дальнюю):

; процедура: АХ= max (АХ, ВХ).

; основная программа.

MAX.

PROC.

FAR.

MOV.

AX, А.

; АХ:=а.

CMP.

AX, BX.

MOV.

ВХ, В.

; ВХ:=b.

JGE.

MAX1.

CALL.

MAX.

; АХ:=mах (а, b).

MOV.

AX, BX.

MOV.

С, АХ.

; сохранить АХ.

МАХ1:

RET.

MOV.

AX, 5.

; АХ:=5.

MAX.

ENDP.

MOV.

ВХ, А.

DEC.

ВХ.

; ВХ:=а-1.

CALL.

MAX.

; AX:=max (5, a-l).

ADD.

С, АХ.

; С:=mах (а, b)+mах (5, а-1).

Передача параметров по ссылке означает передачу адреса (имени) ячейки, соответствующей фактическому параметру, через регистр: основная программа записывает в какой-то регистр адрес фактической переменной, а процедура берет его оттуда. Используют регистры-модификаторы ВХ, ВР, SI или DI, т.к. процедуре придется модифицировать по этому регистру.

Пример 2. Возьмем следующую процедуру на языке Паскаль:

procedure D (var x: integer);.

begin.

x:=x div 16.

end;.

Пусть в программе есть такие обращения к ней: D (A) и D (B), где, А и В-имена переменных, значениями которых являются неотрицательные числа. Используем регистр ВХ: к началу выполнения процедуры в регистре ВХ должен находиться адрес той ячейки (А или В), содержимое которой она изменяет. Доступ к ячейки в этом случае можно получить с помощью конструкции [ВХ].

Фрагмент основной программы, соответствующий обращениям D (A) и D (B):

; процедура.

; основная программа.

D.

PROC.

LEA.

BX, A.

; ВХ=адрес А.

PUSH СХ.

; сохранить cx.

CALL.

D.

D (A).

MOV CL, 4.

LEA.

BX, B.

; ВХ=адрес В.

SHR WORD PTR [BX], CL.

X:=x div 16.

CALL.

D.

; D (B).

POP CX.

; восстановить СХ.

RET.

D.

ENDP.

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

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

2. Передача через стек: программа перед вызовом заносит параметры в стек с помощью команды push. Чтобы подпрограмма могла изменять значения параметров, следует передавать ей не сами значения, а адреса параметров. Используется в случае большого количества параметров.

Выполнение процедуры должно начинаться со следующих команд («входные» действия процедуры):

Р PROC.

PUSH ВР; сохранить ВР.

MOV BP, SP; ВР — на вершину стека.

.

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

После записи в стек старого значения ВР (ВРст) для доступа к параметрам процедуры надо использовать выражение вида [ВР+i], где i=2*n (n — размерность параметра).

При выходе из процедуры стек должен быть в том же состоянии, в каком он был после «входных» действий. Для восстановления состояния стека выполняются «выходные» действия:

POP ВР; восстановить старое значение ВР.

RET 2*k; очистка стека от k параметров-слов и возврат.

Р ENDP.

По команде RET i*k из стека удаляется адрес возврата, затем стек очищается на указанное операндом число байтов и далее выполняется переход по адресу возврата.

Модульная структура программ на языке Ассемблера..

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

Рассмотрим процесс объединения отдельных модулей (оформленных в виде отдельных asm-файлов) в единый загрузочный модуль.

Пусть в программе имеется два модуля Ml и М2. Пусть в модуле М2 описана процедура Р, к которой будет обращаться модуль Ml, и пусть модуль М2 пользуется переменной Х и константой К из модуля Ml. Чтобы при трансляции не возникло сообщение об ошибке «неописанное имя», транслятору ассемблера сообщается, что имена Х и К, хотя и используются в М2, описаны в другом модуле. Такое сообщение делается с помощью директивы.

EXTRN <�имя>:<�тип>,…, <�имя>:<�тип>

где <�тип> - это BYTE, WORD, DWORD, ABS, NEAR, FAR.

В нашем случае в модуле М2 надо указать директиву EXTRN X: BYTE, K: ABS. Она сообщает ассемблеру, что имена Х и К являются внешними по отношению к данному модулю. В модуле Ml следует поместить директиву EXTRN Р: PAR, сообщающую, что Р — это процедура из другого модуля и вызов ее должен быть дальним. В модуле, где описаны имена К и Х (т.е. в Ml) надо поместить директиву PUBLIC <�имя>,…,<�имя>

В данном случае в модуле Ml надо записать директиву PUBLIC X, K. Этой директивой сообщается, что имена Х и К данного модуля разрешено использовать в других модулях. Имена, описанные в модуле и доступные другим модулям, по отношению к этому модулю называются общими. Итак, если в каком-то модуле программы некоторое имя описано как внешнее, то в каком-то другом модуле это имя обязательно должно быть объявлено общим. С учетом сказанного модули Ml и М2 должны иметь следующий вид.

; модуль Ml.

; модуль М2.

EXTRN Р: FAR.

EXTRN X: BYTE, K: ABS.

PUBLIC Х, K.

PUBLIC P.

X.

DB.

P.

PROC.

FAR.

К.

EQU.

MOV.

X, 0.

MOV.

АХ, К.

CALL.

Р.

Модули транслируются отдельно. Затем при компоновке они объединяются в единую машинную программу с помощью команды:

LINK M1. OBJ+ … +Mk.OBJ, M. EXE;

Работа с командой прерываний INT..

Особым видом являются подпрограммы, вызываемые по прерыванию командой INT. Прерывания бывают двух видов:

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

ь программные — создается программами BIOS или DOS для вызова сервисных подпрограмм.

Команда прерывания.

INT number.

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

Процессор выполняет команду прерывания, используя таблицу векторов прерываний. Таблица векторов прерываний занимает самые нижние 1024 байта памяти. Каждый элемент таблицы — это 32-битный адрес «сегмент: смещение», указывающий на подпрограммы операционной системы. Когда происходит вызов команды INT процессор производит следующие действия:

1. Параметр number сообщает процессору местонахождение вектора в таблице векторов прерываний.

2. Процессор передает управление по указанному в векторе прерываний адресу процедуры обработки прерывания (ПОП).

3. Подпрограмма DOS или BIOS, расположенная по указанному адресу начинает выполняться и передает управление назад, когда будет достигнута команда IRET.

4. Команда возврата из прерывания IRET отдает управление вызывающей программе, которая продолжает работу со следующей за прерыванием командой.

Практические задания..

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

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

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

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

4. Разработать программу, которая вводит с клавиатуры число N, затем вводит несколько строк (конец ввода — пустая строка) и формирует новую строку, состоящую из первых N символов каждой введенной строки.

5. Разработать две подпрограммы, одна из которых сравнивает две строки по лексикографическому порядку, а другая обменивает значения двух строк. Разработать программу, которая вводит с клавиатуры несколько строк (конец ввода — пустая строка) и сортирует их в лексикографическом порядке.

6. Разработать подпрограмму, которая разбивает заданную строку на две части: первое слово строки (до первого пробела) и остаток строки (пробелы после первого слова отбрасываются). Разработать программу, которая вводит с клавиатуры строку и выводит каждое слово с новой строки.

7. Разработать подпрограмму, которая переставляет символы заданной строки в обратном порядке. Разработать программу, которая вводит с клавиатуры строку и переставляет в обратном порядке символы в каждом слове (слова разделяются пробелами).

8. Разработать подпрограмму, которая вставляет подстроку в строку, начиная с заданной позиции.

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

10. Разработать две подпрограммы, одна из которых преобразует любую заданную букву в заглавную (в том числе для русских букв), а другая — преобразует букву в строчную.

11. Разработать программу, которая вводит с клавиатуры строку и заменяет первые буквы всех слов на заглавные, а остальные буквы — на строчные.

12. Дано натуральное число п. Вывести на экран все простые числа из отрезка [1, п].

13. Вычислить b=53 +(а+1)-1. Для вычисления хn использовать процедуру возведения в степень через умножение.

14. Описать процедуру sum (x, y, z), которая присваивает вектору z сумму векторов х и у. Использовать ее для вычисления d=a+b+c.

15. Описать процедуру mах (х, у), которая присваивает х большее из целых чисел х и у, а у — меньшее.

16. *Даны три натуральных числа. Определить их наибольший общий делитель.

3. Битовые операции.

Цель: Рассмотреть приемы использования битовых операций при программировании на языке ассемблер.

Задачи:.

ь Изучить синтаксис и приемы использование логические команды: отрицания — NOT, конъюнкции — AND, дизъюнкции — OR, исключающая ИЛИ — XOR и проверки — TEST.

ь Изучить синтаксис и использование команд:

o логических сдвигов влево и вправо — SHL и SHR;

o арифметических сдвигов влево и вправо — SAL и SAR;

o циклических сдвигов влево и вправо — ROL и ROR;

o циклических сдвигов влево и вправо через перенос — RCL и RCR;

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

Логические команды..

Наряду со средствами арифметических вычислений, система команд микропроцессора имеет также средства логического преобразования данных. Под логическими понимаются такие преобразования данных, в основе которых лежат правила формальной логики: отрицание (НЕ), конъюнкцию (И) и дизъюнкцию (ИЛИ).

Логическим командам присущ ряд общих черт:

1. Они реализуют поразрядные операции: i-й разряд результата зависит только от i-х разрядов операндов. При этом одна и та же операция выполняется сразу над всеми разрядами операндов одновременно, параллельно.

2. Формальная логика работает на уровне утверждений истинно и ложно. Во всех логических командах бит 1 трактуется как «истина», а бит 0 — как «ложь». Именно при такой трактовке эти команды и реализуют логические операции отрицания, конъюнкции и дизъюнкции.

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

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

Логические команды:

ь NOT — меняет значение каждого бита операнда на противоположное. Результат записывается на место операнда;

ь AND — производит поразрядное логическое умножение двух операндов и помещает результат в первый операнд;

ь OR — производит поразрядное логическое сложение двух операндов. и помещает результат в первый операнд;

ь XOR — производит поразрядное логическую операцию исключающего ИЛИ над двумя операндами и помещает результат в первый операнд;

ь TEST — аналог команды AND, выполняет поразрядно логическую операцию AND над битами операндов. Состояние операндов остается прежним, изменяются только флаги нуля ZF, знака SF, и четности PF, что дает возможность анализировать состояние отдельных битов операнда без изменения их состояния. Результат логического умножения никуда не записывается.

Синтаксис:.

NOT dst; (dst) < not (dst).

AND dst, src; (dst) < (dst) and (src).

OR dst, src; (dst) < (dst) or (src).

XOR dst, src; (dst) < (dst) xor (src).

TEST dst, src; (dst) test (src).

В этих командах допустимы следующие комбинации операндов:

dst.

src.

r8.

i8, r8, m8.

m8.

i8, r8.

r16.

il6, rl6, ml6.

m16.

il6, rl6.

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

Cодержимое младшей части регистра AX поразрядно умножить на двоичное число 0010 1010b (2Аh).

MOV AL, 0001 1100b; AL = 0001 1100b (1Ch).

AND AL, 0010 1010b; AL = 0000 1000b (08h).

Содержимое младшей части регистра AL логически сложить с содержимым его старшей части.

MOV AL, 1110 1100b; (ECh).

MOV AH, 1010 1010b; (AAh).

OR AL, AH; AL = 1110 1110b (EEh) AH = 1010 1010b (AAh).

Над содержимым АL и числом 1Аh (0001 1010b) произвести операцию исключающее ИЛИ.

MOV AL, 1110 0111b; AL = 1110 0111b (E7h).

XOR AL, 1Ah; AL = 1111 1101b (FDh).

MOV BH, 1100b.

TEST BH, 0011b; = 00b -> ZF=1.

TEST BH, 1010b; = 1000b -> ZF=0.

Над содержимым младшей части регистра AХ выполнить операцию отрицания.

MOV AL, 0001 1100b; AL = 0001 1100b (1Сh).

NOT AL; AL = 1110 0011b (E3h).

Приемы использования логических операций..

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

Установка определенных разрядов в 1..

Для установки определенных разрядов в 1 применяется команда OR dst, maska. В этой команде операнд maska должен содержать единичные биты на месте тех разрядов, которые должны быть установлены в 1 в операнде dst. Например, чтобы установит разряды 3 и 6 аккумулятора AL, нужно использовать маску x1xx1xxx и выполнить команду OR AL, x1xx1xxx b;

Сброс определенных разрядов в 0..

Для сброса определенных разрядов в 0 применяется команда AND dst, maska. В этой команде оператор maska должен содержать нулевые биты на месте тех разрядов, которые должны быть установлены в 0 в операторе dst. Например, чтобы очистить разряды 3 и 6 аккумулятора AL, нужно использовать маску x0xx0xxx и выполнить команду AND AL, x0xx0xxx b;.

Сравнение битов двух операндов..

Для выяснения того, какие биты в двух операндах различаются применяется команда XOR dst, maska. В этой команде операнд maska должен содержать единичные биты на месте тех разрядов, которые сравниваются, а остальные — нулевыми. Например, чтобы сравнить разряды 3 и 6 аккумулятора AL, нужно использовать маску 1 001 000 и выполнить команду XOR AL, 1 001 000 b;.

Инвертирования состояния заданных бит..

Для инвертирования состояния заданных бит в dst также применяется команда XOR dst, src..

Проверки состояния заданных бит..

Для проверки состояния заданных бит операнда применяется команда TEST dst, maska. При этом проверяемые биты операнда dst в операнде maska должны иметь единичное значение. Результатом команды является установка значения флага нуля ZF:

ь если ZF = 0, то в результате логического умножения получился нулевой результат, то есть один единичный бит маски, который не совпал с соответствующим единичным битом dst;

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

Замечание. Для реакции на результат команды TEST целесообразно использовать команду перехода jnz — переход, если флаг нуля zf ненулевой, или команду с обратным действием — jz — переход, если флаг нуля zf = 0..

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

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

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

<�мнемокод> operand, 1; сдвиг operand на 1 разряд.

<�мнемокод> operand, CL; сдвиг орerand на CL разрядов (CL>=0).

Допустимые типы операнда орerand: r8, m8, r16, m16.

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

Команды сдвига меняют все флаги, но, как правило, интерес представляет только флаг переноса CF.

Все команды сдвига можно разделить на команды логического сдвига (или просто сдвига), арифметического и циклического.

Команды логического сдвига SHL и SHR..

К логическим сдвигам относятся две команды:

SHL (Shift Logical Left) — логический сдвиг влево;

SHR (Shift Logical Right) — логический сдвиг вправо.

Синтаксис: SHL dst, count.

SHR dst, count.

В сдвиге участвуют все биты первого операнда dst. При этом бит, уходящий за пределы ячейки, заносится в флаг CF, а с другого конца в операнд добавляется 0. На рисунке 6.1 показан принцип работы этих команд.

Команды сдвига модифицирует флаги переполнения (OF), знака (SF), нуля (ZF), четности (PF) и переноса (CF) в зависимости от результата. Флаг переноса CF содержит значение последнего сдвинутого бита. В однобитных сдвигах флаг переполнения OF = 1, если операция изменила значение старшего бита операнда. При сдвиге на несколько бит состояние флага переполнения OF не определено.

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

SHL BL, 1; сдвигает регистр BL на 1 бит влево.

SHL val16, 1.

SHL byte ptr[si], 1.

SHL AL, CL.

MOV AL, 100 0111b.

SHL AL, 1; AL = 1 000 1110b, CF = 0.

MOV AL, 100 0111b.

SHR AL, 1; AL = 10 0011b, CF = 1.

MOV DH, 11 1000b.

MOV CL, 3.

SHL DH, CL; CF = 1, DH = 1 100 0000b.

Команды арифметического сдвига SAL и SAR..

К командам арифметического сдвига относятся две команды:

SAL (Shift Arithmetic Left) — арифметический сдвиг влево;

SAR (Shift Arithmetic Right) — арифметический сдвиг вправо.

Синтаксис: SAL dst, count.

SAR dst, count.

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

Содержимое операнда сдвигается влево / вправо на количество битов, определяемое значением count. Справа/слева вписываются нули. Команда SAL не сохраняет знака, но устанавливает флаг CF в случае смены знака очередным выдвигаемым битом. В остальном команда SAL полностью аналогична команде SHL.

Команда SAR сохраняет знак, восстанавливая его после сдвига каждого очередного бита. На рис. 6.2 показан принцип работы команд линейного арифметического сдвига.

Команды циклического сдвига: ROL и ROR, RCL и RCR..

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

команды простого циклического сдвига;

команды циклического сдвига через флаг переноса CF.

К командам простого циклического сдвига относятся:

ROL (Rotate Left) — циклический сдвиг влево.

ROR (Rotate Right) — циклический сдвиг вправо.

Синтаксис: ROL dst, count.

ROR dst, count.

Содержимое операнда dst сдвигается влево / вправо на количество бит, определяемое операндом count. Сдвигаемые влево / вправо биты записываются в тот же операнд справа / слева. Схема работы команд простого циклического сдвига показана на рисунке 6.3.

Фрагменты использования логических сдвигов Произвести обмен старшей и младшей половинок операнда размером в байт и слово.

data.

val8 db 0Fh.

val16 dw 1234h.

code.

mov al, 26h.

rol al, 4.

rol val8, 4.

mov ax, 0203h.

rol ax, 8.

rol val16, 8.

К командам циклического сдвига через флаг переноса CF относятся следующие:

RCL (Rotate through Carry Left) — циклический сдвиг влево через перенос;

RCR (Rotate through Carry Right) — циклический сдвиг вправо через перенос.

Синтаксис: RCL dst, count.

RCR dst, count.

Содержимое операнда dst сдвигается влево / вправо на количество бит, определяемое операндом count. Сдвигаемые биты поочередно становятся значением флага переноса CF. Схема работы команд циклического сдвига через флаг переноса CF показана на рисунке 6.4.

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

1. Команды логического сдвига. Используются для выполнения быстрого умножение и деление целых чисел на степени двойки, на 2 k.

Сдвиг двоичного числа на k разрядов влево — это приписывание справа k двоичных нулей, т. е. умножение на 2 k. Например, при сдвиге числа 5 на 3 разряда влево получаем:

5=101b -> 10 1000b = 40 = 5*2 3.

Это же верно и для отрицательных чисел, представленных в дополнительном коде. Например, при сдвиге числа -4 на 1 разряд влево получаем:

доп (-4) = 1 111 1100b -> 1 111 1000b = 100h-8 = доп (-8).

В общем случае умножение на 2 k реализуется так:

MOV CL, k.

SHL dst, CL.

При этом надо учитывать, что все это верно, только если результат сдвига умещается в ячейку. Например, путем сдвига можно реализовать умножение на 2 всех беззнаковых чисел, меньших 128, и всех знаковых чисел от -64 до +63.

Сдвиг на k разрядов вправо — это отбрасывание последних k разрядов, что соответствует получению неполного частного (операции div) от деления на 2 k. Например, при сдвиге числа 18 на 3 разряда вправо получаем:

18 = 10010b-> 10b = 2 = 18 div 2 3.

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

MOV CL, k.

SHR dst, CL.

2. Команда SAR может быть использована для быстрого получения неполного частного при делении знаковых чисел на степени 2. Однако эта операция отличается от той, что реализуется командой IDIV: команда IDIV округляет частное в сторону 0, а SAR округляет в сторону минус бесконечности. Например, при делении -1 на 2 (т.е. при частном -0.5) команда IDIV выдаст ответ 0, а команда SAR — ответ -1:

MOV AL, -1; AL=1 111 1111b.

SAR AL, 1; AL=1 111 1111b (-1).

3. Команды циклического сдвига обычно используются для перестановки частей содержимого ячейки или регистра. Например, поменять местами правую и левую половины регистра AL можно циклическим сдвигом этого байта на 4 разряда влево (или вправо):

MOV AL, 17h; AL=1 0111b.

MOV CL, 4.

ROL AL, CL; AL = 111 0001b = 71h.

4. Команды циклического сдвига через перенос RCL и RCR обычно используются при переносе битов из одного регистра (или переменной) в другой. Например, сдвинуть на 3 разряда влево значения регистров AL и DH, приписав справа к AL три левых бита регистра DH, можно так:

MOV СХ, 3.

L: SHL DH, 1.

RCL AL, 1.

LOOP L.

Абель П. Язык Ассемблера для IBM PC и программирования: пер. с англ. / П. Абель. — М: Высш. шк., 1992. — 447 с.

Ирвин К. Язык ассемблера для процессоров Intel: пер. с англ. / К. Ирвин. — М.: Вильяме, 2002. — 616 с.

Скляров В. А. Программирование на языке Ассемблера: учеб. пособие / В. А. Скляров. — М.: Высш. шк., 1999. — 152 с.

Юров В. Assembler: практикум (+дискета) / В. Юров. — СПб.: Питер Ком., 2002. — 400 с.

Юров В. Assembler: учеб. курс / В. Юров, С. Хорошенко. — СПб.: Питер Ком., 1999. — 672 с.

Показать весь текст
Заполнить форму текущей работой