Главная Случайная страница


Полезное:

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


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






Зсуви та циклічні зсуви





У процесорах 8086 існує множина способів, за допомогою яких можна зсувати біти регістра чи змінної у пам’яті вліво чи вправо. Найпростішим з них є логічний зсув.

Інструкція SHL (зсув ліворуч, синонім – SAL) переміщує кожний біт операнда-приймача на один розряд вліво, у напрямку до самого значущого біту. Наприклад значення 10010110b (96h чи 150 у десятковій уяві) записане у AL, зсувається вліво за допомогою інструкції SHL AL,1. В результаті виходить значення 00101100b (24Ch чи 44 у десятковій уяві), яке записується назад у регістр AL. Флаг переносу встановлюється в значення 1.

Інструкція SAR (арифметичний зсув праворуч) аналогічна інструкції SHR, тільки при її виконанні найбільш значущий біт операнда зсувається праворуч у наступний біт, а потім копіюється назад. Наприклад значення 10010110b (96h чи –106 у десятковій уяві зі знаком), записане у регістрі AL зсувається праворуч за допомогою інструкції SAR AL,1. В результаті виходить значення 11001011b (0CBh чи –53 у десятковій уяві зі знаком), яке записується назад у регістр AL. Флаг переносу встановлюється у значення 0.

Операція ROL має дію, зворотну дії операції ROR. Операнд також зсувається циклічно, але зсув виконується ліворуч. При цьому найбільш значущий біт зсувається у найменш значущий. Інструкції ROR та ROL корисно використовувати для пере упорядковування біт у байті чи у слові. Наприклад, в результаті виконання інструкцій:

 

mov si,49F1h

mov cl,4

ror si,cl

у регістр SI буде записано значення 149Fh: біти 3-0 перемістяться в біти 15-12, біти 7-4 – в біти 3-0 і т.д.

Інструкції RCR та RCL працюють трохи по-іншому. Інструкція RCR аналогічно інструкції зсуву праворуч, при цьому найбільш значущий біт зсувається з флага переносу. Наприклад значення 10010110b (96h чи 150 у десятковій уяві), записане у регістрі AL, циклічно зсувається праворуч через флаг переносу, початкове значення якого дорівнює 1, за допомогою інструкції RCR AL,1. В результаті отримуємо значення 1100101b (0CBh чи 203 у десятковій уяві), яке записується назад у регістр AL. Флаг переносу встановлюється у значення 0.

Інструкція RCL аналогічно, відповідно, лівому зсуву. При виконанні цієї інструкції найменш значущий біт зсувається з флага переносу. Інструкції RCR та RCL корисно використовувати для зсуву операнда, який складається з декількох слів. Наприклад, наступні інструкції виконують множення значення у DX:AX, розміром у подвійне слово на 4:

 

shl ax,1; біт 15 регістру AX зсувається у флаг переносу

rcl dx,1; флаг переносу зсувається у біт 0 регістру DX

shl ax,1; біт 15 регістру AX зсувається у флаг переносу

rcl dx,1; флаг переносу зсувається у біт 0 регістру DX.

 

Інструкції циклічного зсуву, аналогічно інструкціям зсуву, можуть зсовувати операнд на 1 біт чи на число біт, заданих регістром CL.

Безумовні переходи

Головною інструкцією переходу у наборі інструкцій процесора 8086 є інструкція JMP. Ця інструкція вказує процесору 8086, що у якості наступної за JMP інструкцією потрібно виконати інструкцію цільової мітки. Наприклад, після завершення виконання фрагменту програми:

 

mov ax,1

jmp AddTwoToAX

AddOneToAX

inc ax

jmp AxslSet

AddTwoToAX:

inc ax

AxlsSet:

регістр AX,буде містити значення 3, а інструкція ADD та JMP, слідуючи за міткою AddOneToAX, ніколи виконані не будуть. Тут інструкція:

 

AddTwoToAX

 

вказує процесору 8086, що треба встановити покажчик інструкцій IP у значення зміщення мітки AddTwoToAx, тому наступною виконуємою інструкцією буде інструкція:

 

add ax,2

 

Іноді спільно з інструкцією JMP використовується операція SHORT. Для вказівки не цільові мітку інструкція JMP звичайно використовує 16-бітове зміщення. Операція SHORT вказує Турбо Асемблеру, що треба використовувати не 16-бітове, а 8-бітове зміщення (що дозволяє зекономити в інструкції JMP один байт). Наприклад, останній фрагмент програми можна переписати так, що він стане на два байта коротшим:

 

mov ax,1

jmp SHORT AddTwoToAX

AddOneToAX:

inc ax

jmp SHORT AxsSet

AddTwoToAX:

inc ax

AxsSet:

 

Недолік використання операції SHORT (короткий) полягає у тому, що короткі переходи можуть здійснювати передачу керування на мітки, які на віддалі від інструкції JMP не далі, ніж на 128 байтів, тому у деяких випадках Турбо Асемблер може повідомляти вам, що мітка недосяжна за допомогою короткого переходу. До також операцію SHORT має сенс використовувати для посилок вперед, тому що для переходів назад (на попередні мітки) Турбо Асемблер автоматично використовує короткі переходи, якщо на мітку можна перейти за допомогою короткого переходу, та довгі у протилежному випадку.

Інструкцію JMP можна також використовувати для переходу в інший сегмент коду, завантажуючи в одній інструкції і регістр CS, і регістр IP. Наприклад, у програмі:

 

Cseg1 SEGMENT

ASSUME CS:Cseg1

FarTarget LABEL FAR

Cseg1 ENDS

Cseg2 SEGMENT

ASSUME CS:Cseg2

jmp FarTarget

Cseg2 ENDS

 

виконується перехід дальнього типу.

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

 

jmp FAR PTR NearLabel

nop

NearLabel:

 

виконується перехід дальнього типу на мітку NearLabel, хоча ця мітка знаходиться у тім же сегменті коду, що й інструкція JMP.

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

 

mov ax,OFFSET TestLabel

jmp ax

.

.

TestLabel:

 

Тут виконується перехід на мітку TestLabel, так як і у наступному фрагменту:

 

JumpTarget DW TaestLabel

 

jmp [JumpTarget]

.

.

TestLabel:

Умовні переходи

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

Інструкція умовного переходу може здійснювати (чи ні) перехід на цільову (вказану в ній) мітку, в залежності від стану регістру флагів. Роздивимося наступний приклад:

 

mov ah,1; функція DOS вводу з клавіатури

int 21h; отримати наступну

; натиснуту клавішу

cmp al,’A’; чи була натиснута буква ‘A’?

je AwasTyped; якщо так то обробити її

mov [TampByte],al; ні, зберегти символ

.

.

AwasTyped:

push ax; зберегти символ у стекі

 

Спочатку у даній програмі за допомогою функції операційної системи DOS сприймається натиснута клавіша. Потім для зрівняння введеного символу з символом “А” використовується інструкція CMP. Ця інструкція аналогічна інструкції SUB, тільки її виконання ні на що не впливає, тому що призначення даної інструкції полягає у тому, щоб можна було порівняти два операнди, встановивши флаг також, як це робиться у інструкції SUB. Тому у попередньому прикладі флаг нуля встановлюється у значення 1 тільки у тому випадку, якщо регістр AL містить символ А.

Тепер ми підійшли до основного моменту. Інструкція JE представляє собою інструкцію умовного переходу, яка здійснює передачу керування тільки у тому випадку, якщо флаг нуля дорівнює 1. У протилежному випадку виконується інструкція, безпосередньо слідуюча за інструкцією JE (у даному випадку – інструкція MOV). Флаг нуля у даному прикладі буде встановлено тільки у випадку натиснення “А”, і тільки при цьому випадку процесор 8086 перейде до виконання інструкції з міткою AwasTyped, тобто інструкції PUSH.

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

Перелік інструкцій умовних переходів приводиться у табл. 3.2.

 

Таблиця 3.2 – Інструкції умовних переходів

Назва Значення Флажки, що перевіряються
JNB/JNAE Перейти, якщо менш/ перейти, якщо не більш чи дорівнює CF=1
JAE/JNB Перейти, якщо більш чи дорівнює/ перейти, якщо не менш CF=0
JBE/JNA Перейти, якщо менш чи дорівнює/перейти, якщо не більш CF=1 чи ZF=1
JA/JNBE Перейти, якщо більш/ перейти якщо не менш чи дорівнює CF=0 та ZF=0
JE/JZ Перейти, якщо дорівнює ZF=1
JNE/JNZ Перейти, якщо не дорівнює ZF=0
JL/JNGE Перейти, якщо менш ніж/ перейти, якщо не більш ніж чи дорівнює SF=OF
JGE/JNL Перейти, якщо більш ніж чи дорівнює/ перейти, якщо не більш ніж SF=OF
JLE/JNLE Перейти, якщо менш ніж чи дорівнює/ перейти, якщо не більш ніж ZF=1 чи SF=OF
JG/JNLE Перейти, якщо більш ніж/ перейти, якщо не більш ніж чи дорівнює ZF=0 чи SF=OF
JP/JPPE Перейти по парності PF=1
JNP/JPO Перейти по непарності PF=0
JS Перейти по знаку SF=1
JNS Перейти, якщо знак не встановлений SF=0
JC Перейти при наявності переносу CF=1
JNC Перейти при відсутності переносу CF=0
JO Перейти по переповненню OF=1
JNO Перейти при відсутності переповнення OF=0

 

CF – флаг переносу, SF – флаг знаку, OF – флаг переповнення, ZF – флаг нуля, PF – флаг парності

Цикли

Для чого використовуються цикли? Вони служать для роботи з масивами, перевірки стану портів вводу-виводу до отримання певного стану, очистки блоків пам’яті, читання рядків з клавіатури та виводу їх на екран і т.д. Цикли – це головний засіб, який використовується для виконання дій які повторюються. Тому використовуються вони досить часто, настільки часто, що у наборі інструкцій процесора 8086 передбачено фактично декілька інструкцій циклів: LOOP, LOOPNE, LOOPE та JSXZ.

Давайте роздивимось спочатку інструкцію LOOP. Припустимо, ми хочемо вивести 17 символів текстової строки TestString. Це можна зробити наступним чином:

 

TestString DB ‘Це перевірка…’

 

mov cx,17

mov bx,OFFSET TestString

PrintStringLoop:

mov dl,[bx]; отримати наступний

; символ

inc bx; посилка на наступний

; символ

mov ah,2; функція DOS виводу на екран

int 21h; визвати DOS для виводу

; символу

dec cx; зменшити лічильник довжини

; рядка

jnz PrintStringLoop; обробити наступний символ, якщо він є.

 

Але ж є кращій спосіб. Можливо ви пам’ятаєте, що раніше ми говорили о том, що регістр СХ корисно буває використовувати для організації циклів. Інструкція:

 

loop PrintStringLoop

 

робить теж саме, що й інструкції:

 

dec cx

jnz PrintStringLoop

 

однак виконується вона скоріше та займає на один байт менше.

Кожний раз, коли вам потрібно організувати цикл, доки значення лічильника не буде дорівнювати 0, запишіть початкове значення лічильника у СХ та використовуйте інструкцію LOOP.

Як же будуються цикли з більш складною умовою завершення, ніж зворотній відлік значення лічильника? Для таких випадків передбачені інструкції LOOP та LOOPNE.

Інструкція LOOPE працює також, як інструкція LOOP, тільки цикл при її виконанні буде завершуватися (тобто перестануть виконуватися переходи), якщо регістр СХ прийме значення 0 чи флаг нуля буде встановлений у значення 1 (треба пам’ятати про те, що флаг нуля встановлюється у значення 1, якщо результат останньої арифметичної операції був нульовим або два операнди у останній операції зрівняння не збігались). Аналогічно, інструкція LOOPNE завершує виконання циклу, якщо регістр СХ прийняв значення 0 або флаг нуля скинутий (має нульове значення).

Інструкція LOOPE звісна також, як інструкція LOOPZ, інструкція LOOPNE – як інструкція LOOPNZ, також як інструкції JE еквівалентна інструкція JZ (це інструкції – синоніми).

Є ще одна інструкція циклу. Це інструкція JCXZ. Інструкція JCXZ здійснює перехід тільки в тому випадку, якщо значення регістру СХ дорівнює 0. Це дає зручний спосіб перевіряти регістр СХ перед початком циклу. Наприклад, у наступному фрагменту програми, при зверненні до якого регістр ВХ вказує на байт, які потрібно обнулити, інструкція JCXZ використовується для пропуску тіла циклу у тому разі, якщо регістр СХ має значення 0:

 

jcxz SkipLoop; якщо СХ має значення 0,;то нічого робити не треба

ClearLoop:

 

mov BYTE PTR [si],0; встановити наступний байту

; значення 0

inc si; посилка на наступний байт, що

; очищується

SkipLoop:

 

Чому бажано пропустити виконання циклу, якщо значення регістру СХ дорівнює 0? Тому що у протилежному випадку значення СХ буде зменшено до величини 0FFFFh та інструкція LOOP здійснить перехід на вказану мітку. Після цього цикл буде виконуватися 65535 разів. Ви ж бажали, щоб значення регістру СХ, рівне 0, вказувало, що треба обнулити 0 байт, а не 65536. Інструкція JCXZ дозволяє вам у цьому випадку швидко виконати потрібну перевірку.

Date: 2016-05-14; view: 387; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.011 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию