Програмна модель процесора. Опис набору регістрів процесора типу Intel. Регістри користувача 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Програмна модель процесора. Опис набору регістрів процесора типу Intel. Регістри користувача



Програмна модель процесора. Опис набору регістрів процесора типу Intel. Регістри користувача

 

Програмна або регістрова модель – це набір доступних для користувача внутрішніх регістрів процесора. Регістрами називаються області високошвидкісної пам’яті, розміщені всередині процесора в безпосередній близькості до його ядра. Використання регістрів уточнюватиметься в процесі вивчення архітектури процесора і його програмування. В розпорядження програміста надається не дуже багато регістрів, тому вони є критично важливим ресурсом і за їх вмістом потрібно досить уважно слідкувати. Відзначимо, що програмна модель i486 (i486+ – так ми позначатимемо в подальшому всі наступні моделі (архітектури) процесорів типу Intel, вважаючи модель i486 як базову) має 31 регістр: 16 регістрів прикладного програміста і 15 регістрів системного програміста (системні регістри).

Регістри користувача. Ці регістри наведені на рис. 1.1 і функціонально поділяються на декілька груп

31 15 7 0 15 7 0

eax ah ax al
ebx bh bx bl
ecx ch cx cl
edx dh dx dl

 

esp sp
ebp bp
esi si
edi di

Загальні регістри

15 0 31 15 0

сs
ss
ds
es
fs
gs

 

eip ip

Cегментні регістри Вказівник команди

31 15 0

eflags flags

Регістр прапорців

Рис. 1.1 Регістри користувача процесора i486

 

Загальні регістри. Вісім 32-бітових регістрів використовуються для зберігання даних і/або адрес. Буква е в назві означає “розширений” (extended). В командах допускається вказувати їх молодші 16-бітові половини – регістри ax, bx, cx, dx, sp, bp, si, di. Крім того, в перших чотирьох регістрах окремо можна адресувати старші (high) і молодші (low) 8-бітові половини – регістри ah, bh, ch, dh, al, bl, cl, dl. Старші половини 32-бітових регістрів, тобто біти від 16 до 31, регістрів загального призначення не мають визначених назв і тому їх адресувати неможливо (для використання цих частин можна розробити певні програмні засоби). Загальні регістри беруть однаково участь у командах оперування даними і можуть застосовуватися рівноправно в будь-яких режимах адресації. Ці регістри в i486 стали більш універсальними, ніж в процесорах 8086/80286, оскільки перші чотири регістри можна використовувати для адресації операндів. У певних командах ці регістри виконують спеціальні функції, що відображено в їхніх назвах:

eax/ax/al – акумулятор (accumulator) – найчастіше використовується для зберігання проміжних даних. Як правило, команди з використанням цього регістра виконуються дещо швидше і мають меншу довжину. В операціях множення/ділення акумулятор містить множене/ділене до початку виконання операції і добуток/частку після операції. В командах введення-виведення через порти в акумуляторі знаходяться дані, які вводяться-виводяться. Операції з десятковими числами реалізовуються тільки з використанням регістра al.

ebx/bx – (base register) базовий регістр. Містить базову (початкову) адресу об’єкта даних в пам’яті, а також визначає базову адресу таблиці для команди перетворення xlat.

ecx/cx/cl – (counter register) регістр-лічильник у командах повторення (цикли, зсуви, маніпуляції з ланцюжками).

edx/dx – (data segment register) регістр даних. Використовується для зберігання проміжних даних найчастіше, а також в командах множення і ділення (разом з акумулятором). У командах введення-виведення dx містить адресу порта.

esp/sp – (stack pointer register) вказівник стека. Використовується в командах push, pop, а також інших стекових операціях, командах call, ret і iret. Регістр esp/sp адресує вершину стека в поточному сегменті стека.

ebp/bp – (base pointer register) вказівник бази. Використовується для зручності доступу до об’єкта даних у стекові (найчастіше фактичних параметрів підпрограм).

esi/si – (sourse index register) індекс джерела.

edi/di – (destination index register) індекс приймача.

Сегментні регістри. Їх шість 16-бітових регістрів. Вони містять селектори сегментів (segment selector), які асоціюються з різними формами звернення до оперативної пам’яті. Регістри cs, ss, ds, es збереглися незмінними від процесора 8086, а два регістри fs і gs вперше з’явилися в процесорі 80386. Наявність сегментних регістрів пояснюється сегментною організацією пам’яті. В процесорі 8086 максимальний розмір сегмента 64К, в процесорах 80286/80386 та i486+ вміст сегментного регістра визначає сегмент не прямо, а через дескрипторну таблицю (розмір сегмента до 4Г).

cs – (code segment register) сегментний регістр коду. Визначає поточний сегмент, який містить машинні команди (власне програму) і називається кодом.

ss – (stack segment register) сегментний регістр стека. Задає поточний сегмент стека. Вершину стека адресує регістр esp/sp.

ds – (data segment register) сегментний регістр даних. Ідентифікує головний сегмент, який містить дані поточної програми.

es, fs, gs – додаткові сегментні регістри, призначені для задання ще трьох сегментів даних, доступних поточній програмі.

Явна специфікація сегмента в програмі, як правило, не потрібна. Якщо сегмент не вказано за допомогою префікса заміни, то застосовується правила вибору сегмента процесором. Подамо ці правила в наступній таблиці:

 

Тип звернення Використовуваний сегмент Використовуваний регістр Правило вибору сегмента за домовленістю
Команда   Стек   Локальні дані   Ланцюжок – приймач Сегмент коду Регістр cs Сегмент стека Регістр ss Сегмент даних Регістр ds Додатковий сегмент даних Регістр es Автоматично при вибірці команди Всі стекові операції. Всі звернення через esp ebp Усі звернення до даних, крім стекових і ланцюжкових. Приймач в ланцюжкових командах

 

Відзначимо, що префікс заміни сегмента не діє на вибір сегмента за замовчуванням (домовленістю, тобто правилами, вказаними в цій таблиці) в таких випадках:

– для адресації ланцюжків-приймачів використовується тільки регістр es;

– приймач записування в стек або джерело вибору зі стека знаходиться в сегменті, адресованому регістром ss;

– вибір команди здійснюється тільки із сегмента, який адресується регістром cs.

В архітектурі процесора два регістри постійно містять інформацію, яка характеризує стан як процесора, так і програми, команди якої він виконує в даний момент: регістр-вказівник команд eip/ip і регістр прапорців eflags/flags. За допомогою цих регістрів можна обмежено керувати станом процесора.

Вказівник команд. Регістр вказівник команд (instruction pointer register) eip/ip має розрядність 32/16 бітів, містить зміщення наступної команди відносно вмісту регістра сегмента коду cs, тобто використовується для адресації команд в поточному сегменті коду. Цей регістр безпосередньо не доступний програмістові, завантаження і зміна його значення виконуються за допомогою різних команд передачі керування: команд умовного і без умовного переходу, виклику і повернення з процедур, переривань і повернення з переривань. Ми вважатимемо, що після закінчення вибірки з пам’яті поточної команди в регістрі eip/ip формується адреса наступної команди. Хоча це й не так. Процесор i486 не вибирає по одній команді. Він здійснює випереджаючу вибірку вирівняних на межу параграфа 16-байтових блоків коду під час виконання команд. Такі блоки вибираються незалежно від меж між командами (довжини команд різні). До початку виконання команда вже завантажена в процесор і декодована. Це значно підвищує продуктивність процесора. Якщо виконується команда переходу або виклику підпрограми, черга передвибірки команд очищується, процесор вибирає цілий вирівняний блок, який містить адресу призначення (target). Вибрані раніше і декодовані команди втрачаються. Якщо в результаті випереджуючої вибірки виникає особливий випадок (exeption), наприклад. спроба вибірки поза сегментом коду, про це повідомляється до виконання команди, яка зумовила цей особливий випадок. Якщо команда вилучається з черги передвибірки (наприклад, в результаті команди переходу), то про особливий випадок не повідомляється (особливий випадок ігнорується).

Розрядність регістра прапорців (flag register) eflags/flags дорівнює 32/16 бітів. Окремі біти даного регістра мають певне функціональне призначення і називаються прапорцями. Молодша частина eflags/flags повністю еквівалентна регістрові flags процесора 8086.


Структура регістра eflags

Як ми вже відзначали, регістр прапорців eflags має розрядність 32 і його молодші 16 бітів еквівалентні регістрові flags процесора 8086. Наведемо вміст регістра прапорців і охарактеризуємо прапорці.

                       
of df if tf sf zf   af   pf   cf
 
                  13 12
  id vid vif ac vm rf   nt iopl

Рис. 2.1 Регістр прапорців eflags/flags

Прапорці регістра eflags можна розподілити на три групи.

В першу групу входять вісім прапорців стану: cf, pf, af, zf, sf, of, iopl, nt. Ці прапорці можуть змінити своє значення після виконання машинних команд. Вони відображують особливості виконання арифметичних або логічних операцій, тобто стан обчислювального процесу, і можуть бути проаналізовані за допомогою команд умовних переходів і викликів підпрограм. Це наступні прапорці:

– прапорець перенесення (carry flag) cf:

1 – арифметична операція здійснила перенесення зі старшого біта результату, старшим є 7-й, 15-й або 31-й біт у залежності від розмірності операнда;

0 – перенесення не було;

– прапорець парності (parity flag) pf:

1 – вісім молодших розрядів (цей прапорець тільки для восьми молодших розрядів операції операнда будь-якого розміру) результату містять парну кількість розрядів зі значенням 1;

0 – вісім молодших розрядів містять непарну кількість розрядів зі значенням 1;

– допоміжний прапорець перенесення (auxiliary carry flag) af застосовується тільки в командах, операндами яких є BCD-числа. Фіксує факт позичання/перенесення з молодшої тетради результату:

1 – в результаті виконання арифметичної операції додавання відбулося перенесення з розряду 3 в старший розряд або при відніманні було позичання в розряд 3 молодшої тетради зі значення в старшій тетраді;

0 – перенесення в четвертий і позичання в третій розряд молодшої тетради не було;

– прапорець нуля (zero flag) zf:

1 – результат нульовий4

0 – результат не нульовий;

– прапорець знаку (sign flag) sf відображує стан старшого біта операції (відповідно 7-й, 15-й або 31-й біти для 8-, 16- або 32-бітових операндів):

1 – старший біт результату дорівнює 1;

0 – старший біт результату дорівнює 0;

– прапорець переповнення (overflow flag) of використовується для фіксування значущого біта в арифметичних операціях:

1 – за результатом арифметичної операції відбувається перенесення в старший знаковий біт результату або позичання зі старшого знакового біта результату (7, 15 або 31 для 8-, 16- або 32-бітових операндів відповідно);

– рівень привілейованості введення-виведення (input/output privilege level) iopl використовується в захищеному режимі роботи процесора для контролю доступу до команд введення-виведення в залежності від привілейованості задачі;

– прапорець вкладеності задачі (nested task) nt використовується в захищеному режимі роботи процесора для фіксування того факту, що одна задача вкладена в іншу.

Друга група – група прапорців керування має тільки один прапорець df (directory flag) – прапорець напрямку. Він використовується ланцюжковими командами для визначення напрямку опрацювання елементів ланцюжка: від початку ланцюжка (df=0) або від кінця ланцюжка до його початку (df=1). Є команди для роботи з цим прапорцем.

У третю групу регістра eflags входить вісім системних прапорців, які керують введенням-виведенням, маскованими перериваннями, налагодженням, перемиканнями між задачами і режимом віртуального процесора 8086. Наведемо опис цих прапорців:

– прапорець трасування (trace flag) tf використовується для організації покрокової роботи процесора:

1 – процесор генерує переривання з кодом 1 після виконання кожної машинної команди (можна використовувати для налагодження програм, зокрема програмами налагодження;

0 – звичайна робота;

– прапорець переривання (interrupt enable flag) if дозволяє або ні (маскує) апаратні переривання (переривання по входу intr):

1 – апаратні переривання дозволені;

0 – апаратні переривання заборонені;

– прапорець поновлення (resume flag) rf використовується при обробці переривань від регістрів налагодження. Якщо цей прапорець дорівнює 1, то особливі ситуації, які виникли під час налагодження, тимчасово забороняються, щоб призупинити генерацію ще таких же особливих ситуацій. Установлюється в 1 командою iretd з обробника переривання. На прапорець не впливають команди popf, pushf, iret, тобто прапорець привілейований;

– прапорець режиму віртуального процесора 8086 (virtual 8086 mode) vm прапорець віртуального режиму або V-режиму. Найбільш сильно впливає на роботу процесора. Коли vm=0, то процесор може працювати в R-режимі або P-режимі. Якщо vm=1, то процесор переводиться в V-режим, в якому емалюється програмне середовище процесора 8086, тобто i486 перетворюється у високопродуктивний процесор 8086 і можна виконувати декілька програм, розроблених для цього процесора;

– прапорець контролю вирівнювання (alignment check) ac призначений для того, щоб дозволити контроль за вирівнюванням на відповідну межу при зверненні до оперативної пам’яті. Використовується сумісно з бітом am в системному регістрі cr0. Наприклад, Pentium дозволяє вирівнювання даних і команд, починаючи з будь-якої адреси. Якщо потрібно контролювати вирівнювання даних і команд за адресами, які кратні 2 або 4, то установка даних бітів зумовлюватиме те, що при кожному зверненні до оперативної пам’яті за некратними адресами, виникатиме особлива ситуація;

– прапорець віртуального переривання (virtual interrupt flag) vif появився в процесорі Pentium. Якщо процесор працює у V-режимі, то цей прапорець є аналогом прапорця if. Прапорець vif використовується сумісно з прапорцем vip;

– прапорець відкладеного віртуального переривання (virtual interrupt pending flag) vip – появився в процесорі Pentium, установлюється в 1 для індикації відкладеного переривання. Використовується при роботі у V-режимі сумісно з прапорцем vif;

– прапорець ідентифікації (identification flag) id використовується для того, що показати факт підтримки процесором команди cpuid. Якщо програма може встановити цей прапорець 1 або 0, то дана модель процесора підтримує команду cpuid.


Рис. 2.1 Основні типи даних мікропроцесора

· Байт – вісім послідовно розміщених бітів, пронумерованих від 0 до 7. Біт 0 – наймолодший значущий біт.

· Слово – набір з двох байтів, які мають послідовні адреси. Розмір слова – 16 бітів; біти в слові нумеруються від 0 до 15. Байт, в якому нульовий біт, називається молодшим байтом, а байт, в якому 15-й біт, – старшим байтом. Важлива особливість мікропроцесора в тому, що молодший байт завжди зберігається за меншою адресою. Адресою слова вважається адреса його молодшого байта. Адреса старшого байта може бути використана для доступу до старшої половини слова.

· Подвійне слово – набір з чотирьох байтів (32 біти), які мають послідовні адреси. Нумерація цих бітів від 0 до 31. Слово, в якому нульовий біт, називається молодшим словом, а слово, в якому 31-й біт, – старшим словом. Молодше слово завжди зберігається за меншою адресою. Адресою подвійного слова вважається адреса його молодшого слова. Адреса старшого слова може бути використана для доступу до старшої половини подвійного слова.

· Почетверене слово – набір з восьми байтів (64 біти), які мають послідовні адреси. Нумерація бітів від 0 до 63. Подвійне слово, в якому нульовий біт, називається молодшим подвійним словом, а подвійне слово, в якому 63-й біт, – старшим подвійним словом. Молодше подвійне слово завжди зберігається за меншою адресою. Адресою почетвереного слова вважається адреса його молодшого подвійного слова. Адреса подвійного старшого слова може бути використана для доступу до старшої половини почетвереного слова.

· 128-бітовий упакований тип даних появився в мікропроцесорі Pentium III. Для роботи з ним введено спеціальні команди.

Мікропроцесор підтримує також логічну інтерпретацію цих типів даних.

· Цілий тип зі знаком – двійкове число зі знаком розміру 8, 16 або 32 біти. Знак цього числа знаходиться в 7, 15 або 31 біті відповідно. Нуль у цих бітах означає, що число додатне, а одиниця – від’ємне. Від’ємні числа подаються в доповняльному коді. Числові діапазони для цбого типу наступні:

8-розрядне ціле – від до ;

16-розрядне ціле – від до ;

32-розрядне ціле – від до .

· Цілий тип без знаку – двійкове значення без знаку, розміром 8, 16 або 32 біти. Числовий діапазон такий:

байт – від 0 до 255;

слово – від 0 до 65 535;

подвійне слово – від 0 до 4 294 965 295= .

· Вказівник на пам’ять може бути таким:

1. Далекий тип (use16) – 32-розрядна логічна адреса, яка складається з двох частин seg:offset. seg – сегментна складова адреси 16-бітове число, яке завантажується в сегментний регістр, offset – зміщення, яке визначає відстань об’єкта відносно початкової адреси сегмента;

2. Близький тип (use16) – 16-бітова логічна адреса об’єкта – зміщення відносно початку сегмента;

3. Близький тип (use32) – 32-бітова логічна адреса об’єкта – зміщення відносно початку сегмента;

4. Далекий тип (use32) – 48-бітова логічна адреса об’єкта, яка складається з двох частин seg:offset. seg – сегментна складова адреси селектор – 16-бітове число, яке завантажується в сегментний регістр, offset – 32-бітове зміщення, яке визначає відстань об’єкта відносно початкової адреси сегмента.

· Ланцюжок – неперервний набір байтів, слів або подвійних слів максимальної довжини до 4 Гбайтів.

· Бітове поле – неперервний набір бітів, у якому кожний біт незалежний і може розглядатися як окрема змінна. Бітове поле може розпочинатися з будь-якого біта будь-якого байта і може мати довжину до 32 бітів.

· Не упакований двійково-десятковий тип – зображення десяткової цифри від 0 до 9. Не упаковані десяткові числа зберігаються як значення довжиною байт без знаку по одній цифрі в кожному байті. Значення цифри визначається вмістом молодшої тетради.

· Упаковане двійково-десятковий тип – упаковане зображення двох десяткових цифр від 0 до 9 в одному байті. Кожна цифра знаходиться у своїй тетраді. Цифра в старшій тетраді – старша.

· Типи даних з плаваючою крапкою. Співпроцесор (пристрій FPU) має свої типи даних, які несумісні з типами даних цілочислового пристрою. Дивись лекцію, в якій описані типи даних, які підтримуються FPU).

Формат команд. Машинна команда може мати наступні елементи:

1. Поле префіксів – елемент команди, який уточнює або модифікує дії цієї команди в наступних аспектах:

· заміна сегмента, якщо не задовольняє сегмент за замовчуванням;

· зміна розміру адреси;

· зміна розміру операнда;

· вказівка на необхідність повторення даної команди;

2. Поле коду операції, яке визначає дію даної команди.

3. Поле операндів – може містити від 0 до 3 елементів.

Важлива особливість команди це те, що вони не можуть маніпулювати одночасно двома операндами, які знаходяться в оперативній пам’яті (крім ланцюжкових команд і стекових передач).Тому можливі тільки наступні комбінації операндів:

reg, reg

reg, mem

mem, reg

reg, imm

mem, imm

Система переривань. Переривання означає тимчасове призупинення основного процесу обчислень для виконання деяких запланованих або не запланований дій, які викликані роботою апаратури або програми. Ці дії можуть мати сервісний характер, бути запитами з боку програми на виконання обслуговування з боку операційної системи або бути реакцією на нештатні ситуації. Механізм переривань підтримується на апаратному рівні і дозволяє реалізувати як ефективну взаємодію програм з операційною системою, так і ефективне керування апаратною частиною комп’ютера.

Переривання класифікуються так:

· апаратні, які виникають як реакція мікропроцесора на фізичний сигнал деякого пристрою комп’ютера (клавіатура, системний таймер, жорсткий диск і так далі). За часом ці переривання асинхронні, тобто виникають у випадкові моменти часу;

· програмні, які викликаються штучно за допомогою команди з програми (команда int). Вони призначені для виконання дій операційною системою. Ці переривання синхронні;

· винятки – різновид програмних переривань, які є реакцією процесора на нестандартну ситуацію, яка виникла під час виконання деякої команди програми.


Додавання BCD-чисел.

Щоб додати два одно байтових упакованих числа, потрібно виконати дві дії. Спочатку ці два числа сумуються як звичайні двійкові числа за правилами двійкової арифметики, а потім здійснюється корекція результату. Неправильний результат може появитися в двох випадках:

одержана неприпустима тетрада (результат більший 9);

одержана припустима тетрада, але при додаванні виникло двійкове перенесення з вагою 16, у той час як правильна вага перенесення 10.

Перенесення з молодшої тетради фіксується прапорцем af, а зі старшої – прапорцем cf.

Корекцію двійкової суми BCD-чисел, одержаної за допомогою команд add або adc, якщо вона знаходиться в регістрі al, здійснюють командою daa.

Алгоритм корекції:

2.1. Якщо af=1 або молодша тетрада регістра al містить заборонену комбінацію, то до вмісту регістра al додається 06h і прапорець af установлюється рівним 1;

2.2. Якщо сf=1 або старша тетрада регістра al містить заборонену комбінацію, то до вмісту регістра al додається 60h і прапорець сf установлюється рівним 1.

Команда daa діє на всі прапорці, за винятком прапорця переповнення of, стан якого після виконання команди – не визначений.

(al)=25; (bl)=68; add al,bl; (al)=93; sf=af=pf=1; zf=cf=0; of=?.

Віднімання BCD-чисел.

Вважатимемо, що зменшуване знаходиться в регістрі al, а від’ємник у будь-якому одно байтовому загальному регістрі або оперативній пам’яті розміром один байт. Щоб відняти два одно байтових упакованих числа, потрібно виконати дві дії:

1) операнди віднімаються як двійкові числа за допомогою команди sub або sbb так, щоб результат виявився в регістрі al;

2) результат коректується командою das – десяткової корекції після віднімання.

Дія команди das:

3.1. Якщо af=1 або молодша тетрада регістра al містить заборонену комбінацію, то від вмісту регістра al віднімається 06h і прапорець af установлюється рівним 1;

3.2. Якщо сf=1 або старша тетрада регістра al містить заборонену комбінацію, то від вмісту регістра al віднімається 60h і прапорець сf установлюється рівним 1.

Команда das модифікує прапорці як і команда daa.

Оскільки віднімання операндів виконується за алгоритмом додавання зменшуваного з доповняльним кодом від’ємника, то прапорці af і cf в операції віднімання інтерпретуються як прапорці позичання і встановлюються рівними 1 у випадку, коли відповідні перенесення при додаванні зменшуваного і доповняльного коду від’ємника не виникають.

Нехай (al)=10000110b, (ah)=00000111b. За допомогою команди sub al,ah одержимо

10000110b+11111001b=01111111b – зменшуване плюс доповняльний код від’ємника = неправильний результат; cf=0; af=1.

Корекція за командою das:

01111111b–00000110b=01111001b – правильний BCD-результат; sf=0; zf=0; af=1; pf=0; cf=0; of=?.

Відзначимо також, що в разі одержання від’ємної різниці вона подається в десятковому доповняльному коді.

Додавання ASCII-чисел.

Алгоритм додавання таких чисел можна сформулювати так:

1). Одно байтові операнди додаються як двійкові числа командою add або командою adc з одержанням проміжного результату в регістрі al;

2). Корекція результату для додавання ASCII-чисел за допомогою команди aaa, дії якої побудовані з урахуванням реалізації операцій з багато розрядними числами.

Корекція результату додавання складається з наступних кроків:

4.1. Якщо молодша тетрада регістра al містить припустиме десяткове значення і af=0, то перейти до кроку 4.3.

4.2. Якщо молодша тетрада містить заборонену комбінацію або af=1, то необхідно додати 06h до вмісту al, додати 1 до вмісту ah і встановити af рівним 1;

4.3. Встановити старшу тетраду регістра al рівну нулеві;

4.4. Встановити прапорець cf у той же стан, в якому знаходиться прапорець af.

Команда aaa – одно байтова, діє тільки на прапорці af і cf, стани інших прапорців після її виконання – не визначені.

Нехай в регістрах (ax)=0535; (bl)=39. Виконуються команди:

add al,bl

aaa; (ax)=0604; af=1; cf=1.

Віднімання ASCII-чисел.

Алгоритм віднімання таких чисел можна сформулювати так:

1). Одно байтові операнди віднімаються як двійкові числа командою sub або командою sbb з одержанням проміжного результату в регістрі al;

2). Корекція результату для віднімання ASCII-чисел за допомогою команди aas, дії якої побудовані з урахуванням реалізації операцій з багато розрядними числами.

Корекція результату віднімання складається з наступних кроків:

5.1. Якщо молодша тетрада регістра al містить припустиме десяткове значення і af=0, то перейти до кроку 5.3.

5.2. Якщо молодша тетрада містить заборонену комбінацію або af=1, то необхідно відняти 06h від вмісту al, відняти 1 від вмісту ah і встановити af рівним 1;

5.3. Встановити старшу тетраду регістра al рівну нулеві;

5.4. Встановити прапорець cf у той же стан, в якому знаходиться прапорець af.

Команда aas – одно байтова, діє тільки на прапорці af і cf, стани інших прапорців після її виконання – не визначені.

Нехай в регістрах (ax)=0438. Виконуються команди:

add al,35h

aas; (ax)=0403h; af=0; cf=0.

Множення ASCII-чисел.

Команди десяткової корекції для множення і ділення BCD-чисел в мікропроцесорі i486 і наступних моделях цього мікропроцесора відсутні, але якщо використати не упаковану форму або спеціально їх розпакувати, то можна виконувати в мікропроцесорі операції множення і ділення за правилами десяткової арифметики.

Сформулюємо алгоритм множення.

1). Множення одно байтових співмножників, в яких молодші тетради містять двійкові коди десяткових цифр, а старші тетради нульові, за допомогою команди mul. Ця команда формує в регістрі al двійковий добуток;

2). Корекція одержаного результату командою aam, яка перетворює вміст регістра al у дво цифровий добуток: старша цифра в регістрі ah, а молодша в регістрі al, причому молодші тетради містять двійкові коди десяткових цифр, а старші тетради – нульові.

Команда aam ділить вміст регістра al на 10 (0ah) і частку завантажує в регістр ah, а остачу – в регістр al. Стани прапорців sf, zf, pf залежать від вмісту регістра al, а прапорців of, af, cf – не визначені.

(al)=07; (bl)=09;

mul bl;

aam; (ax)=0603; sf=0; zf=0; pf=1; 0f=?; af=?; cf=?.

Ділення ASCII-чисел.

Ділення не упакованих чисел відрізняється від попередніх операцій тим, що необхідна корекція відбувається до операції власне ділення. В дво байтові команді корекції для ділення aad припускається, що в регістрах ah і al знаходиться відповідне дво розрядне ділене, причому ah містить розряд десятків, а регістр al – розряд одиниць, а обидві старші тетради нульові.

1). Спочатку виконується команда aad, яка підготує потрібний дільник в регістрі ax;

2). За нею ділення вмісту регістра ax на одно розрядний дільник можна одержати за допомогою команди div.

Дво байтова команда aad виконує такі дії:

7.1. Вміст регістра ah множиться на 10 (0ah);

7.2. Одержаний результат додається до вмісту регістра al;

7.3. Вміст регістра ah стає рівним нулеві;

7.4. Стани прапорців sf, zf, pf визначаються за результатом в регістрі al, а стани прапорців of, af, cf не визначені.

(ax)=0604; aad; (ax)=0040h; sf=0; zf=0; pf=0; of=?; af=?; cf=?.


Команди передач даних

Команди використовуються для пересилання байтів, слів і подвійних слів з оперативної пам’яті в регістр, з регістра в оперативну пам’ять і з регістра в регістр.

Найпотужнішою серед них є команда mov (MOVe – передати, переслати). Її дія еквівалентна дії оператора присвоєння в мовах високого рівня. Має узагальнене зображення

mov dst, src; dst=(src)

Результат виконання: вміст джерела src (source) dst (destination)

mov reg, imm; завантаження довільної сталої в регістр

mov reg/mem, imm; завантаження довільної сталої в регістр або пам’ять

mov reg/mem, reg; передача з регістра в регістр або пам’ять

mov reg, reg/mem; передача з регістра або пам’яті в регістр

mov sreg, reg/mem16; завантаження сегментного регістра

mov reg/mem16, sreg; збереження сегментного регістра.

Особливості команди.

1. Тільки за допомогою команди mov (і стекових команд) можна завантажувати і зберігати сегментні регістри; тільки в команді mov з регістровою адресацією дозволяється вказувати системні регістри керування cri, налагодження dri і перевірки tri.

2. Неможливо за допомогою mov завантажувати сталу в сегментний регістр; для цього потрібно використовувати як проміжний загальний регістр (найчастіше використовується регістр ax).

3. Коли в команді вказано один з акумуляторів eax/ax/al, її довжина зменшується на 1.

4. В P-режимі завантаження будь-якого сегментного регістра супроводжується читання відповідного дескриптора з таблиці GDT в тіньовий регістр. Тому час виконання команди збільшується. Можуть виникнути особливі ситуації, пов’язані з захистом пам’яті, порушення стека і т. п. Завантаження порожнього селектора в ss зразу ж реєструється особливим випадком.

5. Виконуючи команду mov ss, src, процесор забороняє апаратні переривання (навіть немасковані по входу nmi) на час виконання наступної команди. Вважається, що цією командою буде команда mov sp/esp, src (тобто команда завантаження регістра sp або esp для забезпечення правильної роботи стека).

Команда echg також відносить до загальних передач даних і має узагальнений формат

xchg dst, src;

та форми використання:

xchg reg, reg/mem,

xchg reg/mem, reg.

Тут однією командою забезпечено обмін вмісту джерела і вмісту приймача. Команда має вбудований префікс lock, тобто на час її виконання заблоковано використання загальної шини даних.

Команда xchg прискорює такі алгоритми сортування, в яких вимагається обмін двох елементів масиву в пам’яті. Наприклад, наступні три команди

xchg ax, data1; (data1) в ax, (ax) в data1,

xchg ax, data2; (data1) в data2, (data2) в ax,

xchg ax, data1; (data2) в data1, (ax) – початковий стан

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


Стекові передачі даних

Стек – структура даних, яка використовується для тимчасового зберігання даних і знаходиться в оперативній пам’яті в області поточного сегмента стека. Поточний сегмент стека визначається вмістом двох регістрів: сегментного регістра ss і загального регістра sp (тип сегмента use16) або esp (тип сегмента use32). Вміст регістра ss визначає розміщення в оперативній пам’яті початку сегмента, а вміст sp або esp (надалі писатимемо sp/esp), визначає адресу розміщення вершини стека відносно його початку (останнього елемента записаного в стек). Усі стекові операції автоматично модифікують вміст sp/esp, тобто вершина стека є рухомою.

Операція запису в стек ініціюється командою push src, алгоритм виконання якої можна описати так:

if StackAddrSize=16 * / якщо use16 / * Then */то використати /* sp else esp

if OperandSize=16 * / якщо use16 / * Then

sp/esp=(sp/esp) – 2;

Передати слово (src) у вершину стека ss:[sp/esp];

Else * / OperandSize=32 / *

sp/esp=(sp/esp) – 4;

Передати подвійне слово (src) у вершину стека ss:[sp/esp].

Тут і надалі між подвійними символами * / та подвійними символами / * ми записуватимемо коментар.

Як джерело, тобто src, можна використовувати: сегментний регістр sreg, загальний регістр reg16/32, комірку оперативної пам’яті mem16/32, безпосередню сталу imm16/32.

Три особливості використання команди push src:

1. У процесорі 8086 в стек командою push src записується змінений (sp) зменшений на 2, а в процесорах 80286, 80386 та i486 – (sp/esp) до декремента.

2. Доцільно розширювати 16-бітовий операнд до 32-бітового і записувати його в стек як подвійне слово, інакше може виникнути порушення вирівнювання пам’яті стека на межу подвійного слова.

3. Якщо не вистачає пам’яті для записування в стек, то процесори 80386 та i486 автоматично переходять у стан вимикання (shutdown).

Команда pusha – запису в стек восьми 16-бітових загальних регістрів у порядку: ax, cx, dx, bx, sp, bp, si, di. Для регістра sp в стек записується те значення, яке було до виконання команди pusha. Команда pushad – запису в стек восьми 32-бітових загальних регістрів у порядку: eax, ecx, edx, ebx, esp, ebp, esi, edi. Для регістра esp в стек записується те значення, яке було до виконання команди pushad. Зрозуміло, що одна команда pusha/pushad замінює вісім команд push.

Операція вибору (виштовхування) зі стека ініціюється командою

pop dst, алгоритм виконання якої можна описати так:

if StackAddrSize=16 * / якщо use16 / * Then */то використати /* sp else esp

if OperandSize=16 * / якщо use16 / * Then */то використати /* sp else esp

Передати слово з вершини стека ss:[sp/esp] в dst;

sp/esp=(sp/esp) + 2;

Else * / OperandSize=32 / *

Передати подвійне слово з вершини стека ss:[sp/esp] в dst;

sp/esp=(sp/esp) + 4.

Як dst можна використовувати: сегментний регістр sreg, загальний регістр reg16/32, комірку оперативної пам’яті mem16/32.

На час виконання наступної команди після команди pop ss процесор забороняє апаратні переривання з розрахунком на те, що вона завантажуватиме регістр sp/esp для правильної адресації стека.

Команда вибору зі стека pop sreg ініціює читання у відповідний тіньовий регістр дескриптора з таблиці GDT, який відповідає значенню селектора – вмісту сегментного регістра в sreg. Тому збільшується час виконання команди, можуть виникнути особливі випадки, а також вибір слів зі стека може порушити вирівнювання пам’яті на межу подвійного слова.

Команда popa/popad є двоїстою до команди pusha/pushad відповідно і виштовхує зі стека значення восьми загальних регістрів у зворотному порядку, в якому записувала їхній вміст pusha/pushad. Значення регістра sp/esp при цьому ігнорується.


Таблиця 15.1 Стан прапорців після команди порівняння


Команди множення і ділення

Множення знакових чисел – команда mul. Загальний вигляд команди

mul src; ext:acc=(acc)*(src).

Форма команди

mul reg/mem; Розміри 8/16/32 біти.

Множення байтів: акумулятор – регістр al, 16-бітовий добуток в парі регістрів ah:al. Регістр ah називається розширенням ext (extention) акумулятора al. Якщо src – слово, то акумулятор – регістр ax, розширення акумулятора – регістр dx, тобто 32-бітовий добуток записується в пару регістрів dx:ax. Нарешті, якщо src – 32-бітовий множник, то другий співмножник (або множене) знаходиться в акумуляторі eax, а 64-бітовий добуток записується в пару регістрів edx:eax. Якщо старша половина добутку, тобто вміст розширення акумулятора відмінний від нуля, то прапорці of і cf установлюються в 1, показуючи наявність значущих цифр у старшій половині добутку. Інакше, of=0 і cf=0. Стан інших прапорців не визначений.

Команда множення знакових чисел imul (Integer Multiply) має більше можливостей, ніж команда mul, допускаючи задання одного, двох або трьох операндів. Однооперандна imul (з урахуванням подання операндів і добутку в доповняльному коді) еквівалентна команді mul

imul src; ext:acc=(acc)*(src).

Якщо старша половина добутку не дорівнює розширенню знака молодшої половини, то of=1 cf=1.

Двооперандна imul має вигляд

imul reg, src; reg= (reg)*(src).



Поделиться:


Последнее изменение этой страницы: 2017-01-27; просмотров: 1437; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 44.222.186.148 (0.199 с.)