Знакомство с программой-отладчиком Turbo Debugger. Выполнение простейших команд микропроцессора в среде Turbo Debugger.
Знакомство с программой-отладчиком Turbo Debugger. Выполнение простейших команд микропроцессора в среде Turbo Debugger.
Понятие отладки. Назначение программ-отладчиков
Отладка (debugging) — один из важнейших этапов разработки программного обеспечения (английский термин bug означает"ошибка в программе"). В процессе отладки путем детального анализа в компьютерных программах выявляются и устраняются возможные логические ошибки, которые не обнаруживаются на стадии компиляции.
Отладчики (debugger) — это вспомогательные программы (утилиты), включаемые в набор инструментальных средств программиста для выполнения отладки других программ. Отладчики предоставляют программисту возможность выполнять программу по шагам, следить за изменениями данных и проверять выполнение условий. В зависимости от уровня языка, которым оперирует отладчик, можно выделить два их типа.
Отладчики исходного кода дают программисту возможность видеть текст программы на языке высокого уровня (например, Си), проверять значения отдельных переменных и агрегатов данных (таких, как массивы), используя их имена.
Отладчики машинного уровня отслеживают реально выполняемые машинные команды, отображаемые в виде команд ассемблера. Они позволяют также просматривать содержимое ячеек памяти и регистров микропроцессора.
Отладчик, интегрированный в среду разработки программ пакета Borland C++, относится к первому типу. Turbo Debugger — это отладчик второго типа.
Запуск программы
Запуск программы осуществляется файлом td.exe, расположенный в директории BIN каталога BP или BC.
Структура экрана программы Turbo Debugger
При запуске Turbo Debugger на экране появляется его основное меню и рабочее окно рис.1.
Рабочее окно состоит из следующих четырёх окон:
1. окно команд – CPU;
2. окно регистров и флагов – Registers;
3. окно данных - Dump;
4. окно стека.
|
|
|
|
Рисунок 1
В свою очередь окно Registers поделено на две части. В левой его части указано содержимое всех регистров микропроцессора (ax,bx,cx,dx…), а в правой части показаны биты состояния (флаги-c,z,s,o….).
Последовательное переключение между окнами можно выполнять с помощью клавиши Tab (или Shift+Tab в обратном порядке).
Каждое из окон может быть вызвано самостоятельно на экран, используя пункт меню View и команду соответствующую названию окна (CPU, Registers, Dump).
Задание. Выполнить переключение между окнами, используя разные приемы.
Регистры микропроцессора
Регистры — это небольшие (несколько байт) именованные области памяти микропроцессора, используемые для временного хранения двоичных данных, к которым необходимо обеспечить быстрый доступ.
Каждый регистр может иметь специальное назначение, например, хранить операнды команд микропроцессора, хранить адрес очередной команды программы и т.п. В микропроцессорах Intel для регистров в целом и отдельных групп байт из них принята специальная система обозначений. Например, имеется группа двухбайтовых регистров общего назначения, обозначаемых AX, BX, CX и DX. Например, регистры AX и BX используются микропроцессором для извлечения значений операндов операций сложения и вычитания, а также размещения результатов выполнения соответствующих инструкций.
Как было описано выше, окно Registers поделено на две части. В левой части показано содержимое регистров. Обратим внимание на первые четыре регистра AX, BX, CX, DX, они все равны 0000, четырехзначное число, показанное вслед за именем регистра, является шестнадцатеричным.
Операции с байтами
В микропроцессорах Intel используются двухбайтовые машинные слова. Каждый регистр общего назначения (AX, BX, CX и DX) может хранить одно машинное слово. Однако имеется возможность оперировать с отдельными байтами этих регистров. В этом случае каждый регистр рассматривается состоящим из старшего (High) и младшего (Low) байтов. Обозначения отдельных байтов из регистров состоят из двух букв. Первая задает имя регистра (A, B, C или D), а вторая указывает, какой это байт регистра. Для обозначения старшего байта используется буква H, а младшего — L. Таким образом, регистр AX можно рассматривать, состоящим из двух однобайтовых регистров AH и AL.
Микропроцессор может выполнять арифметические операции над отдельными байтами.
Задание.
Введите в регистр AX число 0102h (два байта) и выполните инструкцию
ADD AH, AL
Каков результат выполнения операции, который будет помещен в регистр AH?
Деление беззнаковых величин
Команды микропроцессора предназначены для выполнения целочисленных операций. Так как деление целых чисел нацело происходит далеко не всегда, то результат деления формируется из двух целых чисел — частного и остатка от деления.
Делимое всегда помещается в пару регистров AX, DX, поэтому в инструкции деления DIV (divide — делить) необходимо указать только регистр с делителем. После выполнения деления регистр AX будет содержать частное, а регистр DX — остаток.
Задание.
Выполните деление числа 7C4B12h (DX=007Ch, AX=4B12h) на 0100h (BX).
Каков результат выполнения операции и почему?
Понятие переполнения
Как и в случае умножения, при выполнении сложения результат может выходить за 16-разрядную сетку (четыре шестнадцатеричных числа). Например, результатом сложения четырехзначных чисел FFFFh и 1h будет пятизначное число 10000h, для записи которого слова (двух байт) недостаточно.
Если результат выполнения операции (над беззнаковыми величинами!) не может быть полностью размещен в регистре, то говорят о возникновении переполнения.
При выполнении сложения беззнаковых чисел суть переполнения (в двоичном представлении) состоит в том, что в результате сложения двух единиц в старшем разряде возникает единица, выходящая за разрядную сетку результирующего регистра. Естественно, что эта единица в регистр помещена быть не может, и при записи в регистр отсекается.
Задание.
Выполните сложение чисел FFFFh (AX) и 1h (BX). Каков результат операции?
Регистр флагов.
Флаг - это бит, принимающий значение 1 ("флаг установлен"), если выполнено некоторое условие, и значение 0 ("флаг сброшен") в противном случае. В ПК используется 9 флагов, причем конструктивно они собраны в один 16-разрядный регистр, называемый регистром флагов и обозначаемый как Flags. Эти биты обозначаются буквами C, P, A, Z, S, T, I, D, O. Например, в текстовый редактор загружен текст. Как только вы внесли в текст первое изменение, можно установить в 1 флаг изменений. После сохранения текста значение флага сбрасывается (0). Тогда при выходе из редактора легко проверить, сохранены ли изменения.
Флаг переноса
Если при сложении беззнаковых чисел происходит переполнение (возникает единица переноса за пределы разрядной сетки регистра), то единичка переноса записывается в Carry Flag. В правой половине окна регистров и флагов (Registers) данный флаг обозначается буквой С. Флаг переноса переустанавливается в каждой операции сложения.
Задание.
Проследите за изменением состояния флага переноса при последовательном выполнении следующих операций
1. FFFF + 1
2. FF00 + 1
Флаг нуля.
Занесите в регистры BX и AX два равных числа, теперь инструкцией SUB произведите вычитание одного числа из другого, в результате чего должен быть установлен флаг нуля Z=1 (Zero Flag).
Флаг знака.
Данный флаг позволяет узнать знак числа. Если вычесть из нуля единицу, то результат будет FFFFh, при этом устанавливается флаг знака S=1 (Sign Flag).
Флаг переполнения.
Флаг переполнения устанавливается в той ситуации, когда этого не должно было произойти. Занесите в регистр AX число 7000h, а в BX 6000h и выполните инструкцию сложения, в результате AX будет содержать число D000h или-12288. Это ошибка, так как результат переполняет слово и является отрицательным, поэтому микропроцессор устанавливает флаг переполнения О=1(Overflow Flag)
Контрольные вопросы
1. Каковы задача и содержание этапа отладки программ?
2. Типы программ-отладчиков и особенности их работы.
3. Понятие регистра микропроцессора и машинного слова.
4. Какая инструкция позволяет выполнять сложение целых чисел? Где размещаются операнды и результат?
5. Какова последовательность выполнения инструкции сложения чисел в среде программы Turbo Debugger?
6. Какая инструкция позволяет выполнять вычитание целых чисел? Где размещаются операнды и результат?
7. В каком виде микропроцессор представляет отрицательные числа? Как будет представлен результат выполнения операции 5h – 8h?
8. Поясните особенности представления и именования двухбайтовых регистров общего назначения в виде совокупности двух однобайтовых.
9. Какими особенностями обладает инструкция умножения целых чисел? Где размещаются операнды и результат?
10. Какими особенностями обладает инструкция деления целых чисел? Где размещаются операнды и результат?
11. Поясните, что означает термин "переполнение". Как выяснить, что при выполнении операции произошло переполнение?
12. Что такое флаг, и для чего он нужен?
13. С помощью какой инструкции, и каким образом происходит сложение с учетом флага переноса?
14. С помощью какой инструкции, и каким образом происходит вычитание с учетом флага переноса?
15. Объясните назначение флагов переноса и нуля?
16. Объясните назначение флагов переполнения и знака?
Аппаратная поддержка языка
При выполнении программы, микропроцессор взаимодействует с оперативной памятью, где хранятся исполняемая программа и данные, а так же с периферийными устройствами.
Программируемая структура процессора
Для организации вычислений микропроцессор i8086 имеет в своём составе 14 шестнадцатиразрядных регистров, которые обеспечивают выполнение программы:
Регистры общего назначения | Сегментные регистры | Специальные регистры | |||||
AH | AL | AX | CS | SP | Указатель стека | ||
BH | BL | BX | DS | BP | Указатель базы стека | ||
CH | CL | CX | ES | IP | Указатель инструкций | ||
DH | DL | DX | SS | FLAGS | Регистр флагов | ||
SI | |||||||
DI |
Регистры общего назначения:
AX(AH, AL), BX(BH, BL), CX(CH, CL), DX(DH, DL) делятся программно на пары однобайтных регистров и могут использоваться для хранения данных. Разбиение на однобайтные регистры позволяет увеличить общее число регистров;
SP, BP – указатель и база стека, соответственно, обеспечивают доступ к данным в стеке, могут использоваться для хранения данных, но делать это не рекомендуется, так как при этом возможно нарушение адресации в стеке, особенно при использовании SP.
SI, DI – шестнадцатиразрядные регистры для хранения данных.
CS, DS, ES, SS – хранят адреса сегментов в памяти, не могут использоваться для хранения данных.
IP – регистр инструкций – хранит адрес (смещение) следующей исполняемой команды.
FLAGS – регистр флагов содержит набор битовых флагов, определяющий текущее состояние процессора и результат выполнения предыдущей команды (таблица 2.1).
Таблица 2.1 | ||
Регистр флагов процессора | ||
Флаг | Название | Назначение |
О | Переполнение | Переполнение при выполнении арифметических операций |
D | Направление | Направление пересылки данных при выполнении строковых команд |
I | Прерывание | Разрешает/Запрещает внешние прерывания |
T | Пошаговый режим | Останов после выполнения каждой команды(используется отладчиками) |
S | Знак | Знак результата выполненной команды(0 – плюс, 1 – минус) |
Z | Ноль | Значение результата выполненной команды(0 – ненулевой, 1 – нулевой) |
A | Внешний перенос | Используется для специальных арифметических операций |
P | Контроль чётности | Число единиц в операнде(0 – нечётное, 1 – нечётное) |
C | Перенос | Содержит перенос из старшего бита при выполнении арифметических операциях |
Структура памяти
Память, с которой взаимодействует процессор при обработке программ, называется Оперативным Запоминающим Устройством (ОЗУ) или Random Access Memory (RAM). Она состоит из набора однобайтных ячеек, обращение к которым происходит по их номерам (физическим адресам). Число ячеек зависит от ширины шины адреса и составляет для процессора i8086 (ширина шины адреса равна 20) 220 – ячеек (1Мбайт). Для современных процессоров с шириной шины адреса 32 объём ОЗУ может доходить до 4 Гбайт.
Данные можно читать или сохранять в ОЗУ байтами, указывая номер требуемой ячейки или словами (2 байта), указывая адрес младшей ячейки памяти и вводя специальный префикс.
Сегментация памяти
Для обращения к памяти процессор предварительно помещает адрес ячейки в один из своих регистров, но для процессора i8086, очевидно нельзя в шестнадцатиразрядном регистре хранить двадцатиразрядный адрес. Поэтому применяют так называемую сегментацию памяти, которая заключается в том, что истинный, физический адрес ячейки хранится в двух регистрах.
Один из них – сегментный, он хранит адрес начала блока памяти, который и называется сегментом. Если к шестнадцати разрядам сегмента мысленно справа дописать четыре двоичных нуля(16+4=20), то получим физический адрес начала сегмента в ОЗУ. Второй регистр хранит величину смещения адреса требуемой ячейки от начала сегмента. Адрес ячейки памяти записывается в виде двойного слова (4 байта): <сегмент>:<смещение>.
Сегмент всегда начинается с ячейки, номер которой заканчивается на 4 двоичных (или один шестнадцатеричный) нуля. Минимальная длина сегмента 16 байтов (параграф). Максимальная длина определяется длиной регистра, хранящего смещение и равна 216(64 Кбайта).
Пара регистров CS:IP(<сегмент>:<смещение>) определяют адрес следующей команды программы.
Для адресации данных используются сегментные регистры DS и ES, а в качестве регистров, хранящих смещение, используются регистры общего назначения BX, SI, DI. Для работы с сегментом стека используют сегментный регистр SS и регистр BP.
Директивы ассемблера
Директивой называется команда транслятору для выполнения определённых данной директивой действий, сама директива в текст транслированной программы не включается.
1. Директива задания исходных данных:
[<имя>] d<тип> <константа>[,<константа>, <константа>, . . .]
· <имя> - имя массива данных, по которому к ним можно обратиться из команды;
· d(define)– определяет начало массива данных;
· <тип> - размер констант, входящих в массив:
b | – | байт, |
w | – | Слово (два байта), |
d | – | двойное слово, |
q | – | учетверённое слово, |
t | – | десять байтов; |
· <константа> - числовой или символьный элемент массива данных.
В ассемблере используется несколько типов констант:
десятичные – последовательность цифр от 0 до 9;
шестнадцатеричные – последовательность шестнадцатеричных цифр от 0 до 9 и от А или а до F или f завершающаяся буквой H или h, первой должна быть десятичная цифра или 0;
восьмеричные – последовательность цифр от 0 до 7, завершающаяся буквами Q или q;
двоичные – последовательность цифр от 0 до 1, завершающаяся буквой B или b;
символьные – символ или группа символов, заключённые в кавычки;
знак ? – используется для резервирования места для данных.
Например,
data1 db 123, 0a2h, 75q, 110011b, 'a', 'пример', ?, ?
Для заполнения больших массивов используется директива dup (duplicate):
<число повторений> dup(<образец>)
<число повторений> - задаёт количество размещаемых в памяти данных, определяемых образцом;
<образец> - любая допустимая группа констант.
Например,
data2 db 23 dup(1, 2, 'x')
выделяет в памяти 23 · 3=69 байтов и заносит в них образец 1, 2, 'x', 1, 2, 'x', … .
2. Директива использования сегментных регистров по умолчанию:
· assume<имя сегментного регистра>:<имя сегмента или nothing>[, <имя сегментного регистра>:<имя сегмента или nothing>, …]
Как отмечалось выше, для задания адреса в памяти требуется два регистра, один из них всегда сегментный, поэтому в команде при обращении к памяти приходится набирать имя сегментного регистра, часто одного и того же. Директива assumeпозволяет избежать этого. Транслятор сопоставляет имя массива данных и автоматически подставляет сегментный регистр, заданный для сегмента, в котором расположен данный массив. Слово nothingпоказывает, что данный сегментный регистр не адресуется по умолчанию. Директива assume может использоваться в программе при каждом изменении сегмента для данного сегментного регистра, но обязательно в начале сегмента, где она задаёт по умолчанию сегментный регистр для сегмента кодов.
Например,
assumecs:code, ds:data1, es:nothing
Здесь code и data1 – имена сегментов кодов и данных, соответственно.
Режимы адресации
1. Регистровая прямая - операнд находится в регистре.
Обозначение - <регистр>,
< регистр > - АХ, ВХ, СХ, DX, SI, DI, BP, SP, AL, BL, СL, DL, AH, BH, CH, DH.
Пример:
mov АХ,SI ; переслать содержимое регистра SI в регистр АХ.
2. Непосредственная -непосредственный операнд (константа) присутствует в команде.
Обозначение - < константное выражение > .
Пример:
mov AX, 093Ah ; занести константу 093Ah в регистр АХ.
3. Прямая - исполнительный адрес операнда присутствует в команде.
Обозначение - < переменная >+/-< константное выражение >.
Пример:
mov AX, WW ; переслать в АХ слово памяти с именем WW
mov BX, WW+2 ; переслать в ВХ слово памяти отстоящее от переменной с именем WW на 2 байта.
4. Регистровая косвенная - регистр содержит адрес операнда.
Обозначение - [< регистр >],
< регистр > - ВХ. ВР. SI, DI.
Пример:
mov [ BX ], CL ; переслать содержимое регистра CL по адресу, находящемуся в регистре ВХ.
5. Регистровая относительная - адрес операнда вычисляется как сумма содержимого регистра и смещения.
Обозначение - < переменная >[< регистр >] или [< регистр >]< константное выражение >,
< регистр > - SI или DI индексная адресация, ВХ или ВР - базовая адресация.
Пример:
mov АХ, WW[SI] ; переслать в АХ слово из памяти, адрес которого вычисляется как сумма содержимого регистра SI и смещения WW.
6. Индексно - базовая - адрес операнда вычисляется как сумма содержимых базового и индексного регистров и смещения.
Обозначение - [< базов. регистр>][< индексн. регистр>] или <переменная >[<базов. регистр >][< индекс. регистр >] или [<базов. регистр >][< индекс. регистр >]< константное выражение,
где < индекс. регистр > - SI или DI, < базов. Регистр > - ВХ или ВР.
Пример:
mov [BX+ SI+ 2], CL; переслать содержимое регистра CL по адресу, вычисляемому как сумма содержимого регистров ВХ, SI и константы 2.
Обработка программ в MS-DOS
Обработка программ на языке ассемблера в MS-DOS состоит из следующих этапов:
§ Создать с помощью текстового редактора файл с текстом программы на языке ассемблера.
§ Транслировать программу с помощью ассемблера TASM (или MASM);
§ Скомпоновать программу с помощью компоновщика (редактора связей) TLINK(или LINK).
§ Запустить программу на выполнение.
Файл исходного текста программы должен иметь расширение asm.
Запуск транслятора осуществляется командой
tasm <исходный файл >[,[< объектный файл >][,[< файл листинга >][,[< файл перекрестных ссылок >]]]][;]
Все создаваемые транслятором файлы будут иметь разные расширения имени, поэтому им можно оставить имя исходного файла:
tasm <исходный файл >, , , , ;
Точка с запятой показывает, какие файлы должен создать транслятор, например, конструкция
tasm <исходный файл >;
создаст только объектный файл.
Расширение объектного файла по умолчанию obj; расширение файла листинга по умолчанию lst; расширение файла перекрестных ссылок по умолчанию crf.
Компоновщик использует, как исходный, объектный файл и создаёт исполняемый файл с расширением по умолчанию exe.
Запуск компоновщика осуществляется командой:
tlink < объектный файл >[,< исполняемый файл >]
В случае сохранения имени исходного файла команда имеет вид:
tlink < объектный файл>
Для запуска под отладчиком необходимо запустить отладчик и загрузить исполняемый файл.
Пример выполнения работы
Вычислить Х = 3А + ( В + 5 ) / 2 - С - 1,
где А, В, С, Х- целые знаковые числа занимающие слово, написать программу реализующую данную формулу.
Распишем формулу по отдельным операциям:
АХ ← А ; значение А в регистре АХ
АХ ← 2 *( АХ ) ; 2А в АХ
АХ ← ( АХ ) + А ; 3А в АХ
ВХ ← В ; В в ВХ
ВХ ← 5 + ( ВХ ) ; В+5 в ВХ
ВХ ← (ВХ ) / 2 ; ( В+5) / 2 в ВХ
АХ ← (BX ) + ( AX ) ; 3А+( В+5 ) / 2 в АХ
АХ ← ( АХ ) - С ; 3А+( В+5 ) / 2 - С в АХ
АХ ← ( АХ ) -1 ; 3А+( В+5 )/2 - С - 1 в АХ
Х ← ( АХ ) ; 3А+( В+5 )/2 - С - 1 в Х
Ниже приведена типичная структура простой программы на ассемблере.
Текст программы:
data segment
a dw 10
b dw 20
c dw 5
x dw ?
data ends
code segment
assume cs: code, ds: data
start: mov ax, data
mov dx, ax ; загрузить адрес
mov ax, a ; сегмента данных
sal ax, 1
add ax, a
mov bx, b
add bx, 5
sar bx, 1
add ax, bx
sub ax, c
dec ax
mov x, ax ; запись результата в память
quit:
mov ax, 4c00h ; код завершения 0
int 21 ; выход в dos
code ends
end start
Варианты заданий
Разработать программу реализующую указанную формулу, исполнить программу с несколькими ( три - четыре) наборами исходных данных, проверить правильность результатов.
1. Х= А - 5 (В - 2С) + 2
2. Х= - 4А + (В + С) / 4 + 2
3. Х= 7А - 2В - 100 + С
4. Х= - А / 2 + 4 (В + 1) + 3С
5. Х= 5 (А - В) - 2С + 5
6. Х= (А/ 2 + В) / 4 + С - 1
7. Х= - (С + 2А + 4В + В)
8. Х= 6С + (В - С + 1) / 2
9. Х= 2 - В (А + В) + С / 4
10. Х= 2В - 1 + 4 (А - 3С)
11. Х= (2А + В) / 4 - С / 2 + 168
12. Х= 6 (А - 2В + С / 4) + 10
13. Х= 5 (А - В ) + С mod 4
14. Х= - ( - (С + 2А) * 4В + 38)
15. Х= А - 3 (А + В) + С mod 4
16. Х= 3(А - 2В) +50 – С / 2
17. Х= (3А + 2В) - С / 4 + 217
18. Х= 3(С - 2A) + (В - С + 1) / 2
19. Х= (2А + В) / 4 - С / 2 + 168
20. Х= 6 (А - 2В + С / 4) + 10
21. Х= 3 (А - 4В ) + С / 4
22. Х= - ( - (С + 2А) * 5В - 27)
23. Х= А / 2 - 3 (А + В) + С * 4
24. Х= 3(А - 2В) +50 – С / 2
25. Х= 5А + 2В - B / 4 + 131
Вопросы по теме
Безусловные переходы
· Инструкция безусловного перехода передаёт управление команде, адрес которой указан в инструкции. Команда безусловного перехода имеет вид
jmp [< тип > ptr ] операнд.
<тип> - тип перехода short (короткий) – смещение 127 байтов вперёд или 128 байтов назад, near (близкий) – смещение в пределах сегмента (64 Кбайта), far (дальний) – в любой сегмент с любым смещением.
ptr– приставка, которую можно перевести как указанный в.
Если тип не задан, по умолчанию принимается near.
Всего можно выделить пять типов безусловных переходов (таблица 3.1).
Таблица 3.1 | ||
Типы команд безусловного перехода | ||
Название | Мнемоника | Описание |
внутрисегментный прямой короткий | jmp short <операнд> | IP ← (IP) + 8-битное смещение, определяемое операндом |
внутрисегментный прямой близкий переход | jmp near ptr <операнд> | IP ← (IP)+16-битное смещение, определяемое операндом |
внутрисегментный косвенный переход | jmp <адрес операнда> | IP ← 16-битный адрес перехода |
Межсегментный прямой далекий переход | jmp far ptr <операнд> | IP ← смещение операнда в сегменте CS ← адрес сегмента, содержащего операнд |
Межсегментный косвенный далёкий переход | jmp far ptr <адрес операнда> | IP ← операнд CS ← адрес операнда +2 |
Условный переход
· Команда условного перехода организует передачу управления при выполнении определённого в команде условия, в противном случае переход осуществляется на команду, следующую за инструкцией условного перехода. Условия определяются текущим состоянием флагов процессора. Каждая из 30 команд условных переходов проверяет определенную комбинацию флагов.
· Все условные переходы являются короткими, т.е. адрес перехода должен отстоять не далее, чем на - 128 или +127 байтов от первого байта следующей команды.
· Команды условной передачи управления и проверяемые при их выполнении условия приведены в таблице 3.2.
Таблица 3.2. | ||
Инструкции условной передачи управления | ||
Мнемокод | условие перехода | |
Флаги | Смысл | |
ja/jnbe jae/jnb jb/jnae jbe/jna je/jz jne/jnz jg/jnle jge/jnl jl/jnge jle/jng jp/jpe jnp/jpo jc jnc jo jno jns js | CF or ZF=0 CF=0 CF=1 CF or ZF=1 ZF=1 ZF=0 (SF xor OF) or ZF=0 SF xor OF=0 (SF xor OF)=1 ((SF xor OF) or ZF)=1 PF=1 PF=0 CF=1 CF=0 OF=1 OF=0 SF=0 SF=1 | выше /не ниже и не равно выше или равно/не ниже ниже/не выше и не равно ниже или равно/не выше равно/нуль не равно/не нуль больше/не меньше и не равно больше или равно/не меньше меньше/не больше и не равно меньше или равно/не больше есть паритет/паритет четный нет паритета/паритет нечетный перенос нет переноса переполнение нет переполнения знак + знак - |
Примечания: | 1. термины “выше” и “ниже” применимы для сравнения беззнаковых величин (адресов); | |
2. термины “больше” и “меньше” используются при учете знака числа; | ||
3. слова xor и or обозначают соответствующие логические операции. |
Циклы
Инструкция, организующая программный цикл имеет вид:
loop[<условие повторения цикла>] <метка короткого перехода>
Инструкция loop использует содержимое регистра СХ как счетчик повторений цикла. Команда loop уменьшает содержимое регистра СХ на 1 и передает управление по адресу, определяемому меткой перехода, если содержимое СХ ≠ 0, в противном случае выполняется следующая за LOOP инструкция. Подобно условным переходам инструкции этой группы могут осуществлять только короткие передачи управления, т.е. в пределах от -128 до +127.
Добавление к инструкции loop<условие повторения цикла> позволяет ввести дополнительные логические условия на повторение цикла:
loope/loopz – повторять, пока ноль;
loopne/loopnz – повторять, пока не ноль.
Проверка флага ZF осуществляется командой loop. Цикл повторяется, если содержимое СХ ≠ 0 и выполняется соответствующее условие, в противном случае выполняется следующая за loop инструкция.
Пример выполнения работы
Дан масив из десяти слов, содержащих целые числа. Требуется найти
максимальное значение в массиве.
Текст программы:
data segment
max dw ?
mass dw 10,24,76,479,-347,281,-24,70,124,97
data ends
code segment
assume cs: code, ds: data
start: mov ax, data
mov ds, ax ; Загрузить сегментный адрес данных
lea bx, mass ; Загрузить адрес смещения массива
mov cx, 10 ; Установить счетчик повторений цикла
mov ax, [bx] ; Первый элемент массива в Аккумулятор
beg: cmp [bx], ax ; Сравнить текущий элемент
; массива с максимальным
jl no ; он меньше
mov ax, [bx] ; он больше или равен
no: inc bx ; Следующий элемент
inc bx ; массива
loop beg
mov max, ax
quit: mov ax,4C00h ; Код завершения 0
int 21h ; Выход в DOS
code ends
end start
Варианты заданий
Дан массив из десяти знаковых чисел (слов или байт). Требуется:
Найти количество отрицательных чисел. Массив байт.
Найти сумму всех положительных и отрицательных чисел. Массив слов.
Найти сумму абсолютных величин. массив байт.
Найти количество положительных чисел. Массив байт.
Поменять местами пары соседних чисел. Массив слов.
Переставить числа в обратном порядке. Массив байт.
Заменить все отрицательные числа нулями. Массив байт.
Найти среднее арифметическое чисел. Массив слов.
Найти количество чисел больших 10h. Массив слов.
Найти наименьшее по абсолютной величине числа. Массив байт.
Найти наибольшее отрицательное число. Массив байт.
Найти произведение положительных элементов последовательности. Массив слов.
Найти среднее арифметическое квадратов ненулевых элементов последовательности. Массив слов.
Найти полусумму наибольшего и наименьшего чисел. Массив байт.
Найти среднее арифметическое отрицательных элементов последовательности. Массив слов.
Найти сколько в массиве чисел больше 12h и меньше 0Afh. Массив байт.
Найти есть ли в массиве два нуля, идущих подряд. Массив слов.
Найти сумму абсолютных величин, меньших 6. Массив байт.
Найти среднее арифметическое чисел больших 10. Массив слов.
Найти сколько чисел равно 12h. Массив байт.
Заменить все отрицательные числа их модулями. Массив байт.
Найти среднее арифметическое положительных чисел. Массив слов.
Найти количество чисел меньших 10h. Массив байт.
Найти наименьшее среди положительных чисел. Массив слов.
Найти наибольшее отрицательное число. Массив байт.
Вопросы по теме
Для чего нужен префикс ptr ?
В чем отличие команд mov ax, offset mass и lea ax, mass?
В чем отличие команд mov ax, bx и mov ax, [bx]?
В чем отличие команд mov ax, [bp] и mov ax, [bx]?
В чем отличие команд mov ax, [bx+2] и mov ax [bx] + 2?
В чем отличие команд mov ax, [bx][si] и mov ax, [si][bx]?
Какие существуют разновидности инструкции jmp?
Как организовать межсегментную передачу управления?
Напишите фрагмент программы условного перехода к метке, лежащей от самого перехода на расстоянии 257 байт.
Для организации каких вычислений служат каманды loop, loope, loopne?
Модифицирует ли какие-нибудь регистры команда loop?
Можно ли организовать цикл по счетчику, не используя команды loop?
Можно ли организовать цикл while с помощью одной из команд loop?
Логические инструкции
not dst
Инструкция not инвертирует все биты байта или слова.
and dst, src
Инструкция and выполняет операции логическое И двух операндов (байтов или слов) и возвращает результат в операнд-приемник. Бит результата устанавливается в 1, если установлены в 1 оба соответствующих ему бита операндов, и устанавливаются в 0 противном случае.
or dst, src
Инструкция or выполняет операции логическое ИЛИ двух операторов (байтов или слов) и помещает результат на место операнда-приемника. Бит результата устанавливается в 1, если равен 1 хотя бы один из двух соответствующих ему битов операндов и устанавливается в 0 в противном случае.
xor dst, src
Инструкция xor выполняет операцию логическое исключающее ИЛИ двух операндов и помещает результат на место операнда-приемника. Бит результата устанавливается в 1, если соответствующие ему биты операндов имеют противоположные значения, и устанавливается в 0 в противном случае.
test dst, src
Инструкция test выполняет логическое И двух операндов (байтов или слов), модифицирует флаги, но результат не возвращает, т.е. операнды не изменяются.
В таблице 4.1. приведены значения регистра флагов, устанавливаемые логическими командами.
Таблица 4.1 | |||||||||||
Логические инструкции | |||||||||||
Мнемокод | Флаги | Действие | |||||||||
Код | Операнды | O | S | Z | A | P | C | ||||
and | dst, src | x | x | u | x | логическое И | |||||
or | dst, src | x | x | u | x | логическое ИЛИ | |||||
xor | dst, src | x | x | u | x | логическое исключающее ИЛИ | |||||
not | Dst | - | - | - | - | - | - | логическое НЕТ | |||
test | dst, src | x | x | u | x | логическое И без изменения dst | |||||
Примечание: | |||||||||||
- | флажок не модифицируется; | ||||||||||
х | Устанавливается или сбрасывается в соответствии с результатом; | ||||||||||
u | не определен; | ||||||||||
Сбрасывается в 0. | |||||||||||
Примеры использования логических команд
Установить 3 и 0 биты в регистре аl, остальные биты не изменять.
or al, 00001001b
Сбросить 4 и 6 битвы в регистре al, остальные биты не изменять.
and al, 10101111b
Инвертировать 2 и 4 биты в регистре al, остальные биты не изменять.
xor al, 00010100b
Перейти на метку LAB, если установлен 4 бит регистра al, в противном случае продолжить выполнение программы.
test al, 00010000b
jnz LAB
продолжаем
. . .
LAB:
Посчитать число единиц в регистре al, рассматривая байт, как набор бит.
mov cx, b ; число сдвигов
xor bl, bl ; обнуление BL
LL: shl al, 1 ; сдвиг влево на один разряд
jnc NO ; переход, если нет переноса
inc bl ; иначе увеличить BL
NO: loop LL ; возврат, если cx ¹0
Пример выполнения работы
Дан массив из 10 байт. Все байты имеют нулевые старшие биты. Необходимо каждый байт содержащий единицу в нулевом бите дополнить до четного числа единиц установкой седьмого бита.
Текст программы:
data segment
NB db 04h, 07h, 14h, 23h, 04h,38h, 3Fh, 2Ah0Dh, 34h
data ends
code segment
assume cs: code. ds:data
START: mov ax, data
mov ds, ax ; Загрузить сегментный адрес данных
lea bx, NB ; bx-текущий адрес массива NB
mov cx, 10 ; cx-счетчик числа интераций
BEG: mov al, [bx] ; считать очередной байт массива
test al, 1b ; установлен ли бит 0?
jz BITOCLR ; нет, бит 0 сброшен
; бит 0 установлен
test al, 0ffh ; четное число единиц?
jp OK ; да, больше ничего делать не надо
or al, 80h ; нечетное дополнить до четного?
jmp short OK
; бит 0 сброшен
BITOCLR: test al, 0ffh ; четное число единиц?
jnp OK ; нет, больше ничего делать не нужно
or al,80h ; нечетное, дополнить до нечетного
OK: mov [bx], al ; записать измененный байт массива
loop BEG
QUIT: mov ax, 4c00h ; Код завершения 0
Int 21h ; Выход в DOS
code ends
end START
Варианты заданий
Дан массив из 10 байт. Посчитать количество байт, в которых сброшены 6 и 4 биты.
Дан массив из 8 байт. Рассматривая его, как массив из 64 бит, посчитать количество единиц.
Дан массив из 8 байт. Рассматривая его как массив логических значений х0 х1 х2 х3 х4 х5 х6 х7 (true-есть ненулевые биты в байте, false-все биты нулевые), вычислить логическую формулу
f=(x7 & x6 & x1) V (x6 & x4 & x2 & x1 & x0) V (x7 & x6 & x3 & x1).
Дан массив из 10 байт. Посчитать количество байт с числом единиц в байте равным три.
Рассматривая байт как набор логических значений x7 x6 x5 x4 x3 x1 x0 (true -1, false - 0), вычислить логическую формулу
f=(x7 & x6 & x3 ) V (x6 & x4 & x2 & x1) V (x7 & x6 & x2 & x0)
Дан массив из 8 байт. Рассматривая