Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ПР 2.doc
Скачиваний:
8
Добавлен:
09.11.2019
Размер:
128.51 Кб
Скачать

Практическая работа №2

«Изучение особенностей выполнения арифметических команд и их влияние на флаги состояния регистра флагов»

Цель работы: изучить форматы и правила работы с командами сложения и вычитания микропроцессора i8086.

Краткие теоретические сведения.

Шестнадцатеричная система счисления

В шестнадцатеричной системе используется шестнадцать цифр и символов: от 0 до 9 и A, B, C, D, E, F. Таблица 1. Десятичная и шестнадцатеричная системы.

Десятичное число

0 1 2 3 4 ... 8 9 10 11 12 13 14 15 16 17

Шестнадцатеричное число

0 1 2 3 4 ... 8 9 A B C D E F 10 11

Десятичное число

26 27 28 29 30 ... 158 159 160 161 162 ... 254 255 256 257

Шестнадцатеричное число

1A 1B 1C 1D 1E ... 9E 9F A0 A1 A2 ... FE FF 100 101

Так как цифры 0..9 используются и в десятичной системе счисления, то для того, чтобы не было путаницы, и компьютер смог бы однозначно отличить одни числа от других, в Ассемблере принято после шестнадцатеричного числа ставить символ h или H (H - это сокращение от англ. hexadecimal - шестнадцатеричное). А после десятичного ничего не ставить. Т.к. числа от 0 до 9 в обоих системах имеют одинаковые значения, то числа, записанные как 5 и 5h одно и тоже.

Пример 1:

  • 1 х 16 = 10h;

  • 10h х 16 = 100h;

100h х 16 = 1000h и т.д.

Регистры процессора

Регистр процессора - это специально отведенная память для хранения какого-нибудь числа. В Таблицах № 2, 4 и 5 приведены списки всех регистров, кроме IP и регистра флагов.

Таблица № 2. Регистры данных

AX

BX

CX

DX

AH

AL

BH

BL

CH

CL

DH

DL

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

AX (Accumulator register - аккумулятор). Применяется для хранения промежуточных данных. В некоторых командах использование этого регистра обязательно

BX (Base register - база). Применяется для хранения базового адреса некоторого объекта в памяти

CX (Count register - счетчик). Применяется в командах, производящих некоторые повторяющиеся действия.

DX (Data register - регистр данных). Так же, как и регистр AX, он хранит промежуточные данные. В некоторых командах его использование обязательно; для некоторых команд это происходит неявно

Эти шестнадцатиразрядные регистры могут хранить числа от 0 до 65.535 (от 0h до FFFFh в шестнадцатеричной системе (вспоминаем прошлую главу)). Под ними идет ряд восьмиразрядных регистров (AH, AL, BH, BL, CH, CL, DH, DL), которые могут хранить максимальное число 255 (FFh). Это половинки (старшая или младшая) шестнадцатиразрядных регистров.

Рассмотрим пример. Допустим, мы выполнили команду mov ax,1234h. В этом случае в регистре ah будет находится число 12h, а в регистре al - 34h. Т.е. AL, BL, CL, DL - это младшие (Low), а AH, BH, CH, DH - старшие (High) половинки шестнадцатиразрядных регистров (см. Таблицу № 3).

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

Команда

Результат

mov ax,1234h

AX = 1234h, AH = 12h, AL = 34h

mov bx,5678h

BX = 5678h, BH = 56h, BL = 78h

mov cx,9ABCh

CX = 9ABCh, CH = 9Ah, CL = 0BCh

mov dx,0DEF0h

DX = 0DEF0h, DH = 0DEh, DL = 0F0h

SI

DI

BP

SP

Таблица № 4. Регистры-указатели

СS

DS

SS

ES

Регистры SI (Source Index register - индекс источника) и DI (Destination Index register - индекс приемника) используются в строковых операциях. Регистры BP и SP необходимы при работе со стеком.

Таблица № 3. Сегментные регистры

Регистр CS служит для хранения сегмента кода программы (Code Segment - сегмент кода);

Регистр DS - для хранения сегмента данных (Data Segment - сегмент данных);

Регистр SS - для хранения сегмента стека (Stack Segment - сегмент стека);

Регистр ES - дополнительный сегментный регистр, который может хранить любой другой сегмент.

Форматы арифметических данных.

Двоичные числа могут иметь 8 или 16 битов и могут быть со знаком или без знака. У числа без знака все 8 или 16 битов представляют его значение. Следовательно, двоичные числа без знака могут принимать значения от 0 до 255 (8-битовые) или до 65535 (16-битовые). У числа со знаком старший бит (7 или 15) указывает его знак, а остальные биты содержат значение числа. Следовательно, числа со знаком могут принимать значения от -128 до 127 (8-битовые) или от -32768 до 32767 (16-битовые).

Десятичные числа

Микропроцессор 8x86 хранит десятичные числа в виде последователь­ностей байтов без знака в упакованном или неупакованном формате. Каждый байт упакованного десятичного числа содержит две цифры а двоично-десятичном коде BCD (binary-coded decimal). При этом код старшей цифры числа занимает четыре старших бита байта. Следовательно, один упакованный десятичный байт может содержать значения от 00 до 99.

Каждый байт неупакованного десятичного числа содержит только один двоич­но-десятичный код цифры в четырех младших битах. Следовательно, один неупа­кованный десятичный байт может содержать лишь значение от 0 до 9. При умноже­нии и делении четыре старших бита должны быть нулевыми, а при сложении или вычитании их значение несущественно.

Хранение чисел в памяти

Микропроцессор 8x86 хранит 16-битовые числа в порядке, противоположном естественному представлению, а именно он хранит младшие биты числа в байте с меньшим адресом. Например, при запоминании числа 1234Н в ячейке по имени NUM он размещает 34Н по адресу NUM, a 12H — по адресу NUM+1. При чтении изображения (или дампа) содержимого памяти учиты­вайте эту схему свертки байтов. Запомните фразу: "младший байт — младший адрес, старший байт — старший адрес".

Команда сложения ADD и команда сложения с добавлением переноса ADC.

Команды ADD (add - сложить) и ADC (add with carry - сложить с переносом) могут складывать как 8-, так и 16-битовые операнды. Команда ADD складывает содержимое операнда-источника и операнда-приемника и помещает результат в операнд-приемник. В символической нотации ее действия можно описать как приемник = приемник + источник

Команда ADC делает то же, что и команда ADD, но при сложении использует также флаг переноса CF, что можно записать следующим образом: приемник = приемник + источник + перенос

Перенос при сложении двоичных чисел аналогичен переносу при сложении десятичных чисел в столбик. Например, при сложении 98+ 13+ 79 = 190 возникает два переноса: сложение единиц вызывает добавление 2 к десяткам, а сложение десятков и перенос из столбца единиц вызывает другой перенос, а именно числа 1 в столбец сотен. Перенос возникает тогда, когда сумма цифр столбца в нем не помещается.

Аналогичным образом возникает перенос, когда ЭВМ складывает двоичные числа: если сумма не помещается в операнде-приемнике, то генерируется перенос. Как известно, 8-битовый регистр может содержать значения без знака в диапазоне от 0 до 255. Если мы, например, выполним двоичное сложение чисел 250 и 10, то получим

1111 1010 (двоичное представление числа 250)

+ 0000 1010 (двоичное представление числа 10)

1 0000 01000 (ответ: десятичное значение 260)

Микропроцессор 8x86 имеет две разные команды сложения. Одна из них (ADD) может складывать значения, представля­емые байтами или словами, а также младшие части значений повышенной точнос­ти. Другая команда (ADC) используется для сложения старших частей значений повышенной точности.

Например, команда ADD AX,CX складывает 16-битовые значения регистров АХ и СХ и возвращает результат в регистр АХ. Если Ваши операнды имеют длину более 16 битов, то можно восполь­зоваться последовательностью команд вида

ADD АХ,СХ ; Сначала сложить младшие 16 битов, а затем

ADC BX,DX ; старшие 16 битов , которая складывает 32-битовое число, находящееся в регистрах СХ и DX, с 32-би­товым числом, находящимся в регистрах АХ и ВХ. Использованная здесь команда ADC добавляет к (DX)+(BX) любой перенос от сложения (СХ)+(АХ).

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

ADD AX,MEM_WORD ;Добавить значение ячейки памяти к регистру

ADD MEM_WORD,AX ;или наоборот

ADD АL,10 ;Добавить константу к регистру

ADD MEM_BYTE,OFH ;или к ячейке памяти

Коррекция результата сложения для представления в кодах ASCII и в упакованном десятичном формате (команды AAA и DAA).

При выполнении сложения микропроцессор 8x86 рассматривает операнды как двоичные числа. Что же произойдет, если они будут двоично-десятичными кодами чисел? При сложении упакованных BCD-чисел 26 и 55 микропроцессор 8x86 выполнит следующее двоичное сложение:

00100110 (BCD-число 26)

+01010101 (BCD-число 55)

01111011 (??)

Вместо правильного значения (BCD-число 81) мы получим результат, у которого старшая цифра 7, а младшая - шестнадцатеричная цифра В. Означает ли это, что нельзя складывать десятичные числа? Нет, это означает лишь то, что результат должен быть скорректирован для представления в десятичной форме.

Коррекция результата сложения десятичных чисел осуществляется командами ААА и DAA (скорректировать сложе­ние для представления в десятичной форме). В них не требуется наличия операн­да: предполагается, что корректируемое значение находится в регистре AL.

Команда ААА преобразует содержимое регистра AL в правильную неупакован­ную десятичную цифру в младших четырех битах регистра AL (и заполняет нуля­ми старшие четыре бита). Она используется в следующем контексте:

ADD AL,BL ;Сложить неупакованные числа, находящиеся в AL и BL

ААА ; и преобразовать результат в неупакованное число

Если результат превышает 9, то команда ААА добавляет 1 к содержимому регист­ра АН (чтобы учесть избыточную цифру) и полагает флаг CF равным 1; в против­ном случае она обнуляет флаг CF. Кроме того, команда ААА изменяет состояние флага AF и оставляет значения флагов PF, ZF, SF и OF неопределенными. Но так как в данном случае только флаг CF имеет смысл, то считайте значения остальных флагов уничтоженными.

Команда DAA преобразует содержимое регистра AL в две правильные упако­ванные десятичные цифры. Она используется в следующем контексте:

ADD AL,BL ;Сложить упакованные BCD-числа в AL и BL

DAA ; и преобразовать результат в упакованное число

Команда приращения значения приемника на единицу

Команда INC (прирастить) добавляет 1 к содержимому регистра или ячейки памяти, но в отличие от команды ADD не воздействует на флаг переноса CF. Команда INC удобна для приращения значений счетчиков в циклах команд. Ее можно использовать и для приращения значения индексного регистра или указателя при доступе к последовательно расположенным ячейкам памяти.

INC CX ;Прирастить значение 16-битового

INC AL ;или 8-битового регистра

INC MEM_ВYТЕ ;Прирастить значение байта

INC MEM_WORD[BX] ;или слова памяти

Команды вычитания. Выполнение вычитания микропроцессором 8086.

Внутри микропроцессора 8x86, как и любого другого микропроцессора общего назначения, нет устройства вычитания. Однако он имеет устройство сложения (сумматор) и может вычитать числа путем сложения. Чтобы понять, как можно вычитать путем сложения, посмотрим, как вычесть 7 из 10. В начальной школе учат записывать это как 10-7, но в старших классах (скажем, в курсе алгебры) учат и другому способу записи:10+(-7).

Первым способом (непосредственное вычитание) вычитание может быть выпол­нено микропроцессором, имеющим устройство вычитания. Так как микропроцес­сор 8x86 его не имеет, то он вычитает в два приема. Сначала он меняет знак у вычитаемого (у второго числа), т.е. обращает его, а затем складывает уменьшае­мое и обращенное вычитаемое.

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

Применяя это к нашему примеру, получаем 8-битовые представления чисел 10 и 7: 00001010В и 00000111В соответственно. Затем дополним двоичное представле­ние 7 до двух:

1111 1000 (обратить все биты)

+_____1 (добавить 1)

1111 1001 (дополнение до двух числа 7, или - 7).

Теперь операция вычитания примет следующий вид:

0000 1010 (10)

+1111 1001 (-7)

0000 0011 (Ответ: 3)

Команда вычитания SUB и вычитания с заемом SBB.

Команды SUB (substract - вычесть) и SBB (substract with borrow - вычесть с заемом) аналогичны соответственно командам сложения ADD и ADC, только при вычитании флаг переноса CF действует как признак заема. Команда SUB вычитает операнд-источник из операнда-приемника и возвращает результат в операнд-приемник, т.е. приемник = приемник — источник

Команда SBB делает то же самое, но дополнительно вычитает значение флага переноса CF:

приемник = приемник - источник - перенос

Как и в случае сложения, команды вычитания выполняют две отдельные функ­ции. Первая команда SUB вычитает числа размером в байт или слово, а также младшие биты чисел повышенной точности. Другая команда SBB вычитает старшие биты чисел повышенной точности. Например, команда SUB AХ,СХ вычитает содержимое регистра СХ из содержимого регистра АХ и возвращает результат в регистр АХ.

Если размеры операндов превышают 16 битов, то пользуйтесь последователь­ностью команд вида

SUB AX,BX ;Вычесть младшие 16 битов,

SBB BX,DX ; а затем — старшие 16 битов

Здесь мы вычитаем 32-битовое число, помещенное в регистры СХ и DX, из 32-бито­вого числа, помещенного в регистры АХ и ВХ. При вычитании содержимого регист­ра DX из содержимого регистра ВХ команда SBB учитывает возможность заема при выполнении первого вычитания.

Можно вычитать из содержимого регистра содержимое ячейки памяти (и наоборот) или вычитать из содержимого регистра либо ячейки памяти непосредст­венное значение.

SUB AХ,MEM_WORD ; Вычесть из регистра содержимое ячейки памяти

SUB MEM_WORD[BX],AХ ; или наоборот

SUB AL,10 ; Вычесть константу из регистра

SUB MEM_BYTE,OFH ; или из ячейки памяти

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

Команда уменьшения содержимого приемника на единицу DEC

Команда DEC (decrement - уменьшить) вычитает 1 из содержимого регистра или ячейки памяти, но при этом (в отличие от команды SUB) не воздейст­вует на флаг переноса CF. Команда DEC часто используется в циклах для умень­шения значения счетчика до тех пор, пока оно не станет нулевым или отрицатель­ным. Ее можно использовать также для уменьшения значения индексного регистpa или указателя при доступе к последовательно расположенным ячейкам памя­ти.Примеры:

DEC CX ;Уменьшить знамение 16-битового

DEC AL ; или 8-битового регистра

DEC MEM_BYTE ;Уменьшить значение байта

DEC MEM_WORD[BX] ;или слова памяти

Индивидуальное задание

Примечания:

– char – 8 битн. со знаком;

– un. char – 8 битн. без знака

– int – 16 битн. со знаком

– un. int – 16 битн. без знака

– long – 32 битн. со знаком

– un. long – 32 битн. без знака

Исходные данные:

    • дата рождения студента в формате ДД-ММ- ГГ - числа – d, m, g (байт)

    • возраст студента ( количество полных лет ) – число v (байт)

Задание:

1. Составить программу вычисления у по формуле:

Номер варианта

Формула

Номер варианта

Формула

Номер варианта

Формула

1

y=4m+3d-g*v+5

9

y=2m+8-g*d+5v

17

y=g*m-7d+v-20

2

y=5d-g*v+7m-2

10

y=d*g-4v+5m-1

18

y=3-m*d+4g-5v

3

y=m*g+d-2v+10

11

y=5m-7+d*g+2v

19

y=5v-d*m+6g+3

4

y=v*d-3m+4+3g

12

y=5-g*m+8d-3v

20

y=9d-2g+v*m-1

5

y=8m-3d+4+g*v

13

y=4v+d*m-3g+1

21

y=7m+g*d-5v+4

6

y=g*m-4d+8v-7

14

y=9-m*d-4g+7v

22

y=2+m*d-3g+7v

7

y=2v+6d-m*g+3

15

y=2m-7g+4-d*v

23

y=d*m-4v+3g-2

8

y=3+d*g-v+4m

16

y=5d+g*v-6m+9

24

y=4g+7m-d*v-8

  1. Для контроля за правильностью работы программы использовать готовый модуль IO.ASM

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

; практическая работа 2

; Работа выполнена студентом Ивановым И.И., гр. А123

4. Просмотреть влияние на флаги регистра при пошаговом выполнении программы(отобразить в отчете).

; **********************************************************

; Исходные данные: дата рождения - 28-03-82 -> d=28 m=3 g=82

; данные типа byte

; Программа выполняет расчет по формуле: z = 2d - gm

; ----------------------------------------------------------

model small

Include io.Asm ; подключение модуля io.Asm

.stack 100h

.data

d db 28

m db 3

g db 82

z dw ? ; для результата

.code

start: ; точка входа в программу

mov ax,@data ; загрузка адреса сегмента данных

mov ds,ax

mov al,2 ; 2  al

mul d ; ax := al * d (=2d)

mov z,ax ; 2d  z

mov al,g ; g - al

mul m ; gm  ax

sub z,ax ; в z - результат вычисления

outint z ; вывод z (если z может быть отрицательно)

или outword z ; вывод z (если z неотрицательно)

mov ax,4C00h ; завершение работы

int 21h

end start

Модуль io.Asm (Ввод-вывод числовых данных)

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

Рассматриваемый модуль приведен в книге В.Н.ПИЛЬЩИКОВА «Ассемблер».

Ввод с клавиатуры

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

Команды ввода не выдают на экран никакого приглашения к вводу, поэтому сама программа должна выдавать символы приглашения (например, символ >).

***************************************************************************

Ввод числа: inint ор

Допустимый тип операнда op: слово из регистра или из памяти.

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

Если число набрано без знака или со знаком "плюс", то оно вводится как число без знака и может иметь величину от 0 до 2 16-1.

Если перед числом указан знак "минус", то оно вводится как отрицательное число и должно иметь величину от -2 15 до -1.

Концом числа считается любой символ, отличный от цифры.

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

Так как введенное число всегда записывается в регистр или ячейку размером в слово, то, например, команда ININT АХ допустима, а команда ININT АН - нет.

************************************************************************

Очистка буфера ввода: flush

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

Вывод на экран

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

**************************************************************************

Переход на новую строку: newline

Аналог процедуры writeln языка Паскаль: по этой команде курсор перемещается на начало следующей строки экрана.

***************************************************************************

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]