Характеристика команд для опрацювання цілочисельних даних

Інформація про навчальний заклад

ВУЗ:
Національний університет Львівська політехніка
Інститут:
Не вказано
Факультет:
ЗІ
Кафедра:
Не вказано

Інформація про роботу

Рік:
2024
Тип роботи:
Практична робота (завдання)
Предмет:
Системне програмування та операційні системи

Частина тексту файла (без зображень, графіків і формул):

системне програмування Практична робота № 4 Характеристика команд для опрацювання цілочисельних даних Система команд Intel8086 1. Арифметичні команди  2. Логічні операції: AND,OR,XOR,NOT,TEST. 3. Команди зсуву. 3.1. Логічний зсув: SHL зсув вліво (на місце молодших бітів стають „0”). SHR зсув вправо (на місце старших бітів стають „0”). 3.2. Арифметичний зсув: SAL зсув вліво (на місце молодших бітів стають „0”). SAR зсув вправо (розмноження знакового розряду). 3.3. Циклічний зсув: ROL циклічний зсув вліво. ROR циклічний зсув вправо. RCL циклічний зсув вліво з участю CF. RCR циклічний зсув вправо з участю CF. 4. Команди керування програмою. 4.1. Команда безумовного переходу JMP. Дана команда додає значення вказане в операнді до значення в регістрі IP, який містить адресу команди, що розташована після JMP. Відповідно, якщо здійснюється перехід назад, то значення операнду буде від’ємне, якщо вперед – додатне. 4.2. Оператор циклу LOOP. Передає керування на мітку, вказану як операнд, поки значення в регістрі CX не стане рівне нулю. Існують додатково також різновиди цієї команди: LOOPE(або LOOPZ) – передає керування за адресою, вказаною в операнді якщо CX містить нульове значення і встановлений прапорець нуля, тобто ZF=1. LOOPNE(або LOOPNZ) передає керування за адресою, вказаною в операнді якщо CX містить нульове значення і прапорець нуля скинуто, тобто ZF=0. 4.3. Команди умовних переходів. Працюють аналогічно до JMP та LOOP, за винятком того, що довжина переходу повинна бути в межах від -128 до +128 байт. Переходи для беззнакових даних. Мнемоніка Опис Прапорці, що перевіряються  JE/JZ Перехід, якщо рівно/нуль ZF  JNE/JNZ Перехід, якщо не рівно/не нуль ZF  JA/JNBE Перехід, якщо вище/не нижче або рівно ZF,CF  JAE/JNB Перехід, якщо вище або рівно/ не нижче CF  JB/JNAE Перехід, якщо нижче/не вище або рівно CF  JBE/JNA Перехід, якщо нижче або рівно/не вище CF,AF   Будь яку перевірку можна закодувати двома мнемо кодами. Наприклад JB та JNAE генерують однаковий об’єктний код, хоча позитивну перевірку JB легше зрозуміти аніж заперечну JNAE. Переходи для знакових даних. Мнемоніка Опис Прапорці, що перевіряються  JE/JZ Перехід, якщо рівно/нуль ZF  JNE/JNZ Перехід, якщо не рівно/не нуль ZF  JG/JNLE Перехід, якщо більше/не менше або рівно ZF,SF,OF  JGE/JNL Перехід, якщо більше або рівно/ не менше SF,OF  JL/JNE Перехід, якщо менше/не більше або рівно SF,OF  JLE/JNG Перехід, якщо менше або рівно/не більше ZF,SF,OF   Команди переходу для умови рівно або нуль (JE/JZ) та не рівно або не нуль (JNE/JNZ) існують як для знакових так і для без знакових даних. Стан рівно/нуль наступає незалежно від знаку. Спеціальні арифметичні перевірки. Мнемоніка Опис Прапорці, що перевіряються  JS Перехід, якщо є знак(від’ємне) SF  JNS Перехід, якщо немає знаку(додатнє) SF  JC Перехід, якщо є перенос (аналогічно JB) CF  JNC Перехід, якщо немає переносу CF  JO Перехід, якщо є переповнення OF  JNO Перехід, якщо немає переповнення OF  JP/JPE Перехід, якщо паритет парний PF  JNP/JP Перехід, якщо паритет непарний PF   Ще одна команда умовного переходу перевіряє чи рівний вміст регістра CX нулю. Ця команда повинна знаходитися безпосередньо після арифметичної команди чи команди порівняння. Одним з можливих місць застосування команди JCXZ може бути початок циклу, де вона перевіряє чи не містить регістр CX нульового значення. Таким чином, ми розглянули основні команди, що можуть бути корисні при обчисленні арифметичних виразів як над знаковими, так і над без знаковими даними. Зупинимось детальніше на командах додавання та множення. Додавання й віднімання Команди ADD і SUB виконують додавання й віднімання байтів або слів, що містять двійкові дані. Віднімання виконується у комп'ютері по методу додавання із двійковим доповненням: для другого операнда встановлюються зворотні значення бітів і додається 1, а потім відбувається додавання з першим операндом. У всьому, крім першого кроку, операції додавання й віднімання ідентичні. Можливі п'ять ситуацій: ADD / SUB регістр-регістр; ADD / SUB пам'ять-регістр; ADD / SUB регістр-пам'ять; ADD / SUB регістр-безпосереднє значення; ADD / SUB пам’ять-безпосереднє значення. Переповнення. При виконанні арифметичних операцій можливе переповнення. Один байт містить знаковий біт і сім біт даних, тобто значення від -128 до +127. Результат арифметичної операції може легко перевищити розрядність однобайтового регістра. Наприклад, результат додавання в регістрі AL, що перевищує його розрядність, автоматично не переходить у регістр AH. Припустимо, що регістр AL містить 60h, тоді результат команди ADD AL,20h генерує в AL суму -.80h. Але операція також встановлює прапорець переповнення і прапорець знаку у стан "негативно". Причина в тому, що.80h або двійкове 1000 0000 є від’ємним числом. Т.ч. в результаті, замість +128, ми одержимо -128. Оскільки регістр AL занадто малий для такої операції то варто скористатися регістром AX. Для розширення AL до AX можна скористатися командою CBW (Convert Byte to Word - перетворити байт у слово). CBW ADD AX,20H Але повне слово має також обмеження: один знаковий біт і 15 біт даних, що відповідає значенням від -32768 до +32767. Розглянемо далі як можна обробляти числа, перевищуючі ці межі. Додавання багатобайтних чисел Наведемо універсальну процедуру додавання двох чисел довільної розмірності, використовуючи додавання окремих слів. При цьому слід: 1) забезпечити сусідство слів; 2) виконувати обробку від молодшого до старшого слова; 3) завантажити в регістр CX кількість слів, що будуть додаватися Дія починається з додавання наймолодших полів, тобто тих слів, що розташовані в пам’яті за молодшими адресами. У першому циклі додаються ліві слова, а у другому - слова, розташовані правіше. При цьому адреси в регістрах SI, DI і BX збільшуються на 2. Цю операцію виконують по дві команди INC для кожного регістра. Застосовувати команду ADD reg,02 у цьому випадку не можна, тому що при цьому буде очищений прапорець переносу, що приведе до спотворення результату додавання. Оскільки використовується цикл, виконується лише команда додавання ADC. Перед циклом команда CLC (CLear Carry - очистити прапор переносу) установлює нульове значення прапорця переносу. DOSSEG .MODEL SMALL .STACK 100h .DATA X DW 1111h, 2222h Y DW 3333h,4444h Z DW 3 dup(0) .CODE mov ax,@data mov ds,ax clc mov cx,2 lea si,X lea di,y lea bx,z l1: mov ax,[si] adc ax,[di] mov [bx],ax inc si inc si inc di inc di inc bx inc bx loop l1 adc [bx],0 cmp [bx],0 je Lexit mov [bx],0ffffh Lexit: mov ah,4Ch int 21h Беззнакові й знакові дані. Числові поля можуть трактуватися як знакові, або як беззнакові. Це контролюється при написанні програми самостійно. Для беззнакових величин всі біти є бітами даних і замість обмеження +32767 регістр може містити числа до +65535. Для знакових величин лівий біт є знаковим. Команди ADD і SUB не роблять різниці між знаковими і беззнаковими величинами, вони просто додають і віднімають біти. Наприклад при додаванні двох двійкових чисел, одне з яких містить одиничний лівий біт можливе такі випадки. Для беззнакового числа біти представляють додатнє позитивне число 249, для знакового – від’ємна число -7: Беззнакове Знакове  11111001 249 -7  00000010  2 +2  11111011 251 -5   Двійкове представлення результату додавання однакове для беззнакового й знакового числа. Однак, біти представляють +251 для беззнакового числа й -5 для знакового. Таким чином, числовий вміст поля може інтерпретуватися по різному. Стан "перенос" виникає в тому випадку, коли є пеpенос у знаковий розряд. Стан "переповнення" виникає у тому випадку, коли перенос у знаковий розряд не створює переносу з розрядної сітки або перенос із розрядної сітки відбувається без переносу в знаковий розряд. При виникненні переносу при додаванні беззнакових чисел, результат одержується неправильний: Беззнакове Знакове CF OF  11111100 252 -4    00000101 5 +5    00000001 1 1 1 0   (неправильно)      При виникненні переповнення при додаванні знакових чисел, результат виходить неправильний: Беззнакове Знакове CF OF  01111001 121 +121    00001011 11 +11    10000100 132 -124 0 1    (неправильно)     При операціях додавання й віднімання може одночасно виникнути й переповнення, і перенос: Беззнакове Знакове CF OF  11110110 246 -10    10001001 137 -119    01111111 127 +127 1 1   (неправильно) (неправильно)     Таким чином, в попередній програмі перенос, що може виникати при додаванні найстарших слів, слід трактувати для беззнакових даних як значущий біт і враховувати його в загальній сумі, а для знакових, вважати ознакою від’ємного числа. Таким чином, універсальна програма для додавання знакових чисел повинна у випадку від’ємного результату заміняти найстарше слово результату. Для віднімання багатобайтних чисел слід використовувати команду SBB (віднімання з запозиченням), яка є еквівалентом ADD. Множення Операція множення для беззнакових даних виконується командою MUL, а для знакових - IMUL (Integer MULtiplication - множення цілих чисел). У єдиному операнді команд MUL і IMUL вказується множник. Відповідальність за контроль над форматом чисел, що обробляються і за вибір відповідної команди множення лежить на самому програмісті. Існують дві основні операції множення: "Байт на байт". Множене перебуває в регістрі AL, а множник у байті пам'яті або в однобайтовом регістрі. Після множення добуток перебуває в регістрі AX. Операція ігнорує і витирає будь-які дані, які були в регістрі AH. AX=AL*регістр8/пам’ять8 "Слово на слово". Множене перебуває в регістрі AX, а множник - у слові пам'яті або у двобайтному регістрі. Після множення добуток знаходиться в подвійному слові, для якого потрібно два регістри: старша (ліва) частина добутку - в регістрі DX, а молодша (права) частина - в регістрі AX. Операція ігнорує й стирає будь-які дані, які перебували в регістрі DX. DX:AX=AX* регістр16/пам’ять16 Розглянемо наступну команду: MUL MULTR Якщо поле MULTR визначене як байт (DB), то операція припускає множення вмісту AL на значення байта з поля MULTR. Якщо поле MULTR визначене як слово (DW), то операція припускає множення вмісту AX на значення слова з поля MULTR. Якщо множник перебуває в регістрі, то довжина регістра визначає тип операції, як це показано нижче: MUL CL ; Байт-множник: множене в AL, добуток в AX. MUL BX ; Слово-множник: множене в AX, добуток DX:AX. Команда IMUL призначена для множення чисел зі знаком. Формат її використання аналогічний MUL. Якщо множник і множене мають однаковий знак, то IMUL та MUL генерують однаковий результат, а якщо множники мають різні знаки, то команда MUL виробляє доданій результат, а команда IMUL – від’ємний. Для підвищення ефективності операції множення, при множенні на степінь числа 2 більш доцільним є зсув вліво на необхідну кількість бітів. Зсув більше ніж на один розряд потребує параметру у регістрі CL. Наприклад: Множення на 2 SHL al,1 Множення на 8: MOV CL,3 SHL AX,CL Множення багатобайтних чисел Наведемо процедуру множення двох подвійних слів. При цьому слід: 1) забезпечити сусідство слів; 2) виконувати обробку від молодшого до старшого слова; 3) забезпечити достатній розмір для результату, тобто чотири слова. dosseg .model small .stack 100h .data X DW 5678h,1234h ;елементи даних Y DW 0deffh,9abch Z DW 0,0,0,0 .code mov ax,@data mov ds,ax CALL F10XMUL mov ah,4Ch int 21h F10XMUL PROC MOV AX,X MUL Y MOV Z,AX MOV Z+2,DX MOV AX,X+2 MUL Y ADD Z+2,AX ADC Z+4,DX ADC Z+6,00 MOV AX,X MUL Y+2 ADD Z+2,AX ADC Z+4,DX ADC Z+6,0 MOV AX,X+2 MUL Y+2 ADD Z+4,AX ADC Z+6,DX RET F10XMUL ENDP end Ділення Операція ділення для беззнакових даних виконується командою DIV, a для знакових - IDIV. Відповідальність за вибір відповідної команди лежить на програмісті. Існують дві основні операції ділення: "Слово на байт". Ділене перебуває в регістрі AX, а дільник - у байті пам'яті або а однобайтовому регістрі. Після ділення остача виходить у регістрі AH, а частка - в AL. Оскільки однобайтова частка дуже мала (максимально +255 (.FFh) для беззнакового ділення і +127 (7Fh) для знакового), то дана операція має обмежене використання. AX  /  регістр8 = AL(частка) AH(остача) AX  /  пам’ять8 = AL(частка) AH(остача) "Подвійне слово на слово". Ділене перебуває в регістровій парі DX:AX, а дільник - у слові пам'яті або в регістрі. Після ділення остача виходить у регістрі DX, а частка в регістрі AX. Частка в одному слові допускає максимальне значення +32767 (FFFFh) для беззнакового ділення і +16383 (7FFFh) для знакового. DX(старша частина)  AX(молодша частина)  /  регістр16 = DX(остача) AX(частка) DX(старша частина)  AX(молодша частина)  /  пам’ять16 = DX(остача) AX(частка) У єдиному операнді команд DIV і IDIV вказується дільник. Розглянемо наступну команду: DIV DIVISOR Якщо поле DIVISOR визначене як байт (DB), то операція припускає ділення слова на байт. Якщо поле DIVISOR визначене як слово (DW), те операція припускає ділення подвійного слова на слово. При діленні, наприклад, 13 на 3, виходить результат 4 1/3. Частка є 4, а остача - 1. Зауважимо, Команда DIV ділить беззнакові числа і відповідно генерує без знаковий результат. Знаковий ділення: Команда IDIV (Integer DIVide) виконує ділення знакових чисел. Таким чином, якщо ділене й дільник мають однаковий знаковий біт, то команди DIV і IDIV генерують однаковий резуультат . Але, якщо ділене й дільник мають різні знакові біти, то команда DIV генерує додатну частку, а команда IDIV – від’ємну частку. Зауважимо, що для підвищення продуктивності, при діленні на степінь числа 2 (2, 4, і т.д.) варто використовувати зсув вправо на відповідну кількість війкових розрядів. Переповнення й переривання Використовуючи команди DIV і особливо IDIV, дуже легко викликати переповнення Переривання до непередбачених результатів. В операціях ділення передбачається, що дільник значно менший, ніж ділене. Ділення на нуль завжди викликає переривання. Але ділення на 1 генерує частку, що дорівнює діленому, що може також легко викликати переривання. Рекомендується використати наступне правило: якщо дільник - байт, то його значення повинне бути більше, ніж лівий байт (AH) діленого; якщо дільник - слово, то його значення повинне бути більше, ніж ліве слово (DX) діленого. Проілюструємо дане правило для дільника, рівного 1: Операція ділення: Ділене Дільник Частка Слово на байт: 0123 01 (1)23 Подвійне слово на слово: 4026 0001 0001 (1)4026 В обох випадках частка перевищує можливий розмір. Для того щоб уникнути подібних ситуацій, корисно вставляти перед командами DIV і IDIV відповідну перевірку (CMP). Для команди IDIV дана логіка повинна враховувати той факт, що або ділене, або дільник можуть бути від’ємними, а порівнюються абсолютні значення, тому необхідно використати команду NEG для тимчасового перетворення від’ємного значення в додатне Ділення відніманням Якщо частка занадто велика, то ділення можна виконати з допомогою циклічного віднімання. Метод полягає в тому, що дільник віднімається з діленого й у цьому ж циклі частка збільшується на 1. Віднімання триває, поки ділене залишається більше ніж дільник. При такому методі, дуже велика частка й малий дільник можуть викликати тисячі циклів. SUB CX,CX ;Очищення частки C20: CMP AX,BX ;Якщо ділене < дільника, JB C30 ; то вийти SUB AX,BX ;Віднімання дільника від діленого INC CX ;Інкремент частки JMP C20 ;Повторити цикл С30: RET ;Частка в CX, остача в AX Наприкінці підпрограми регістр CX буде містити частку, а AX – остачу від ділення. Якщо частка отримується в регістровій парі DX:AX, те необхідно зробити два доповнення: 1. У мітці C20 порівнювати AX і BX тільки при нульовому DX. 2. Після команди SUB вставити команду SBB DX,00. ASCII та BCD формат та робота з ними. Дані, що вводять із клавіатури, мають ASCII-формат, наприклад, букви SAM мають у пам'яті шістнадцяткове подання 53414D, цифри 1234 – 31323334h. У багатьох випадках формат алфавітних даних, наприклад, ім'я людини або опис статті, не міняється в програмі. Але для виконання арифметичних операцій над числовими значеннями, такими як 31323334h, потрібна спеціальна обробка. За допомогою наступних ассемблерных команд можна виконувати арифметичні операції безпосередньо над числами в ASCII-форматі: AAA (ASCII Adjust for Addition - корекція для додавання ASCII-коду) AAD (ASCII Adjust for Division - корекція для ділення ASCII-коду) AAM (ASCII Adjust for Multiplication - корекція для множення ASCII-коду) AAS (ASCII Adjust for Subtraction - корекція для віднімання ASCII-коду) Ці команди кодуються без операндів і виконують автоматичну корекцію в регістрі AX. Корекція необхідна, тому що ASCII код представляє, так званий, розпакований десятковий формат, у той час, як комп'ютер виконує арифметичні операції у двійковому форматі. Додавання в ASCII-форматі Розглянемо процес додавання чисел 8 і 4 в ASCII-форматі: 38h+34h=6Ch. Отримана сума неправильна ні для ASCII-формату, ні для двійкового формату. Однак, ігноруючи ліву 6 і додавши 6 до правої .Ch: Ch + 6 =12h - одержимо правильний результат у десятковому форматі. Цей приклад злегка спрощено, але він добре демонструє процес, що виконує команда AAA при корекції. Для прикладу, припустимо, що регістр AX містить 0038h, а регістр BX - 0034h. Числа 38 і 34 представляють два байти в ASCII форматі, які необхідно додати. Додавання й корекція кодується наступними командами: ADD AL,BL ;Додати 34 і 38 AAA ;Корекція для додавання ASCII кодів. Команда AAA перевіряє праву шістнадцяткову. цифру (4 біти) у регістрі AL. Якщо ця цифра знаходиться між Ah і Fh або прапорець AF дорівнює 1, то до регістра AL додається 6, а до регістра AH додається 1, прапорці AF і CF встановлюються в 1. У всіх випадках команда AAA встановлює в 0 ліву шіст. цифру в регістрі AL. Результат - у регістрі AX: Після команди ADD: 006C Після команди AAA: 0102 Для того, щоб отримати остаточне ASCII-значення, досить просто поставити трійки на місце лівих шістнадцяткових цифр: OR AX,3030H ;Результат 3132 Все показане вище представляє додавання однобайтовых чисел. Додавання багатобайтних ASCII-чисел вимагає організації циклу, що виконує обробку справа наліво із врахуванням переносу. Приклад , показаний нижче, додає два трибайтні ASCII-числа в чотирибайтну суму. . TITLE ASCADD (COM) Додавання в ASCII-форматі ASSUME CS:CODESG,DS:CODESG,SS:CODESG ORG 100H BEGIN: JMP SHORT MAIN ASC1 DB '578' ; Елементи даних ASC2 DB '694' ASC3 DB '0000' MAIN PROC NEAR CLC LEA SI,AASC1+2 ; Адреса ASCII-чисел LEA DI,AASC2+2 LEA BX,AASC1+3 MOV CX,03 ; Виконати 3 цикли A20: MOV AH,00 ; Очистити регістр AH MOV AL,[SI] ; Загрузить ASCII-байт ADC AL,[DI] ; Додавання (з переносом) AAA ; Корекція для ASCII MOV [BX],AL ; Збереження суми DEC SI DEC DI DEC BX LOOP A20 ; Виконати 3 цикли MOV [BX],AH ; Зберегти перенос RET MAIN ENDP CODESG ENDS END BEGIN Зверніть увагу на наступне: У програмі використається команда ADC, тому що будь-яке додавання може викликати перенос, що повинен бути доданий до наступного (лівого) байту. Команда CLC установлює прапорець CF у нульовий стан. Команда MOV очищає регістр AH у кожному циклі, тому що команда AAA може додати до нього одиницю. Команда ADC враховує пеpеноси. Зауважте, що використання команд XOR або SUB для обнулення регістра AH змінює прапорець CF. Коли завершується кожний цикл, відбувається пересилання вмісту pегистра AH (00 або 01) у лівий байт суми. В результаті виходить сума у вигляді 01020702. Програма не використає команду OR після команди AAA для занесення лівої трійки, тому що при цьому встановлюється прапорець CF, що змінить результат команди ADC. Одним з рішень у цьому випадку є збереження регістра прапорців за допомогою команди PUSHF, виконання команди OR, і, потім, відновлення регістра прапорців командою POPF: ADC AL,[DI] ;Додавання з переносом AAA ;Корекція для ASCII PUSHF ;Збереження прапорців OR AL,30H ;Запис лівої трійки POPF ;Відновлення прапорців MOV [BX],AL ;Збереження суми Замість команд PUSHF і POPF можна використати команди LAHF (Load AH with Flags - завантаження прапорців у регістр AH) і SAHF (Store AH in Flag register - запис прапорців з регістра AH у регістр прапорців). Команда LAHF завантажує в регістр AH прапорці SF, ZF, AF, PF і CF; а команда SAHF записує вміст регістра AH у зазначені прапорці. У наведеному прикладі, однак, регістр AH уже використовується для арифметичних переповнень. Інший спосіб вставки трійок для одержання ASCII-кодів цифр - організувати обробку суми командою OR у циклі. Віднімання в ASCII-форматі Команда AAS (ASCII Adjust for Subtraction - корекція для Віднімання ASCII-кодів) виконується аналогічно до команди AAA. Команда AAS перевіряє праву шіст.цифру (чотири біти) в регістрі AL. Якщо ця цифра лежить між A і F або прапорець AF дорівнює 1, то з регістра AL віднімається 6, а з регістра AH віднімається 1, прапорці AF і CF встановлюються в 1. У всіх випадках команда AAS встановлює в 0 ліву шіст. цифру в регістрі AL. У наступних двох прикладах передбачається, що поле ASC1 містить 38h, а поле ASC2 – 34h: Приклад 1: AX AF  MOV AL,ASC1 ;0038   SUB AL,ASC2 ;0034 0  AAS ;0004 0   Приклад 2: AX AF  MOV AL,ASC2 ;0034   SUB AL,ASC1 ;00FC 1  AAS ; FF06 1   У прикладі 1 команді AAS не потрібно виконувати корекцію. В прикладі 2, оскільки права цифра в регістрі AL дорівнює Ch, команда AAS віднімає 6 від регістра AL і 1 з регістра AH та встановлює в 1 прапорці AF і CF. Результат (який повинен дорівнювати -4) має шістнадцяткове подання FF06, тобто десяткове доповнення числа -4. Множення в ASCII-форматі Команда AAM (ASCII Adjust for Multiplication - корекція для множення ASCII кодів) виконує коректування результату множення ASCII кодів у регістрі AX. Однак, шістнадцяткові цифри повинні бути очищені від трійок і отримані дані уже не будуть ASCII-кодами. (так званий розпакований десятковий формат). Наприклад, число в ASCII-форматі 31323334 має розпаковане десяткове подання 01020304. Крім цього, треба пам'ятати, що корекція здійснюється тільки для одного байта за одне виконання, тому можна множити тільки oднобайтові поля; для довгих полів необхідна організація циклу. Команда AAM ділить вміст регістра AL на 10 (0Ah) і записує частку в регістр AH, а остачу в AL. Припустимо, що в регістрі AL знаходиться 35h, а в регістрі CL – 39h. Наступні команди множать вміст регістра AL на вміст CL і перетворюють результат в ASCII-формат:  AX  AND CL,0FH ;Перетворити CL в 09   AND AL,0FH ;Перетворити AL в 05 0005  MUL CL ;Помножити AL на CL 002D  AAM ;Перетворити в розпакований десятковий. 0405  OR AX 3030H ;Перетворити в ASCII-ф-т 3435   Команда MUL генерує 45 (002Dh) у регістрі AX, після чого команда AAM ділить це значення на 10, записуючи частку 04 у регістр AH і остачу 05 у регістр AL. Команда OR перетворює розпаковане десяткове число в ASCII-формат. Наступний приклад демонструє множення чотирибайтового множеного на однобайтовий множник. Оскільки команда AAM працює тільки з однобайтовими числами, то в програмі організований цикл, що обробляє байти справа наліво. Остаточний результат множення в даному прикладі - 0108090105. Якщо множник більший одного байта, то необхідно забезпечити ще один цикл, що обробляє множник. В цьому випадку простіше буде перетворити число з ASCII-формату у двійковий формат TITLE ASCMUL (COM) Множення в ASCII-форматі CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG ORG 100H BEGIN: JMP MAIN ; --------------------------------------------- MULTCND DB '3783' ; Елементи даних MULTPLR DB '5' PRODUCT DB 5 DUP(0) ; --------------------------------------------- MAIN PROC NEAR MOV CX,04 ;4 цикли LEA SI,MULTCND+3 LEA DI,PRODUCT+4 AND MULTPLR,0FH ; Забрати трійку A20: MOV AL,[SI] ; Загрузити ASCII-символ ; (можна LODSB) AND AL,OFH ; Забрати трійку MUL MULTPLR ; Помножити AAM ; Корекція для ASCII ADD AL,[DI] ; Додати до AAA ; збереженого MOV [DI],AL ; добутку DEC DI MOV [DI],AH ; Записати перенос DEC SI LOOP A20 ; Повторити 4 рази RET MAIN ENDP CODESG ENDS END BEGIN Ділення в ASCII-форматі Команда AAD (ASCII Adjust for Division - корекція для ділення ASCII-кодів) виконує коректування ASCII коду діленого до безпосереднього ділення. Однак, спочатку необхідно очистити ліві трійки ASCII-кодів для одержання розпакованого десяткового формату. Команда AAD може оперувати із двохбайтовим діленим в регістрі AX. Припустимо, що регістр AX містить ділене 3238 в ASCII- форматі,а регістр CL містить дільник 37 також в ASCII- форматі. Наступні команди виконують корекцію для подальшого ділення: AND CL,0FH ;Перетворити CL у розпакований формат АХ  AND AX,0F0FH ;Перетворити AX у розпакований формат 0208  AAD ;Перетворити у двійковий 001C  DIV CL ;Поділити на 7 0004   Команда AAD множить вміст AH на 10 (0Ah), додає результат 20 (14h) до регістра AL і очищає регістр AH. Значення 001C є шістнадцятковим еквівалентом десяткового числа 28. Дільник може бути тільки однобайтовий від 01 до 09. Наступний приклад виконує ділення чотирибайтового діленого на однобайтовий дільник. У програмі організований цикл обробки діленого справа наліво. Остача від ділення залишається в регістрі AH і команда AAD коректує її в регістрі AL. Остаточний результат: частка 00090204, а в регістрі AH остача 02. Якщо дільник більше одного байта, то необхідно утворити інший цикл для обробки дільника, але доцільніше перетворити у двійковий формат і ділити в ньому. TITLE ASCDIV (COM) Ділення в ASCII-форматі CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG ORG 100H BEGIN: JMP SHORT MAIN DIVDND DB '3698' ;Елементи даних DIVSOR DB '4' QUOTNT DB 4 DUP(0) MAIN PROC NEAR MOV CX,04 ; 4 цикли SUB AH,AH ; Стерти лівий байт діленого AND DIVSOR,0FH ; Забрати трійку в дільнику LEA SI,DIVDND LEA DI,QUOTNT A20: MOV AL,[SI] ; Загрузити ASCII байт ; (можна LODSB) AND AL,0FH ; Забрати трійку AAD ; Корекція для ділення DIV DIVSOR ; Ділення MOV [DI],AL ; Зберегти частку INC SI INC DI LOOP A20 ; Повторити 4 рази RET MAIN ENDP CODEGS ENDS END BEGIN Двійково-десятковий формат У попередньому прикладі ділення в ASCII-форматі була отримана частка 00090204. Якщо стиснути це значення, зберігаючи тільки праві цифри кожного байта, то одержимо 0924. Такий формат називається двійково-десятковим (BCD - Binary Coded Decimal) (або упакованим). Він містить тільки десяткові цифри від 0 до 9. Довжина двійково-десяткового представлення вдвічі менша за ASCII-формат. Зауважими, що десяткове число 0924 має основу 10 і, будучи перетвореним у основу 16 (тобто в шістнадцятковий формат), дасть 039Ch. Можна виконувати додавання й віднімання чисел в двійково-десятковому форматі (BCD-форматі). Для цих цілей є існуються дві команди корекції: DAA (Decimal Adjustment for Addition - десяткова корекція для додавання) DAS (Decimal Adjustment for Subtraction - десяткова корекція для віднімання) Обробка полів також здійснюється по одному байту за одне виконання. Приклади розв’язку задач. Задача1. Написати програму, яка обчислює арифметичний вираз і результат записує в пам’ять Z=(X4-16)-(Y2+75)/5, де X,Y- операнди зі знаком і довжиною в байтах, згідно індексу. DOSSEG .MODEL SMALL .STACK 100h .DATA X DW 1234h, 5678h Y DW 9abch Z DW 3 dup(0) .CODE mov ax,@data mov ds,ax mov dx,X+2 mov ax,X sub ax,16 sbb dx,0 push dx push ax xor ax,ax xor dx,dx mov ax,Y add ax,75 adc dx,0 mov bx,5 idiv bx mov bx,ax pop ax pop dx sub ax,bx sbb dx,0 mov z,ax mov z+2,dx mov ah,4Ch int 21h end Процедура яка передбачає, що введений дільник може бути значно менший за ділене і тому використання стандартної команди DIV неможливе. Така процедура повинна використовувати віднімання, поки старша частина діленого не стане меншою ніж дільник (процедура MY_DIV). Для ділення подвійного слова на слово: MY_DIV proc sub cx,cx sub bx,bx mov dx,X+2 mov ax,X M_D1: cmp dx,Y jl M_D3 sub ax,Y sbb dx,00 add cx,01 adc bx
Антиботан аватар за замовчуванням

29.05.2014 22:05-

Коментарі

Ви не можете залишити коментар. Для цього, будь ласка, увійдіть або зареєструйтесь.

Ділись своїми роботами та отримуй миттєві бонуси!

Маєш корисні навчальні матеріали, які припадають пилом на твоєму комп'ютері? Розрахункові, лабораторні, практичні чи контрольні роботи — завантажуй їх прямо зараз і одразу отримуй бали на свій рахунок! Заархівуй всі файли в один .zip (до 100 МБ) або завантажуй кожен файл окремо. Внесок у спільноту – це легкий спосіб допомогти іншим та отримати додаткові можливості на сайті. Твої старі роботи можуть приносити тобі нові нагороди!
Нічого не вибрано
0%

Оголошення від адміністратора

Антиботан аватар за замовчуванням

Подякувати Студентському архіву довільною сумою

Admin

26.02.2023 12:38

Дякуємо, що користуєтесь нашим архівом!